File:  [LON-CAPA] / capa / capa51 / pProj / capalogin.c
Revision 1.4: download - view: text, annotated - select for diffs
Wed Mar 22 21:08:03 2000 UTC (24 years, 5 months ago) by albertel
Branches: MAIN
CVS tags: HEAD
- Lots of little changes

    1: /* Copyright 1992-1997 Michigan State University, Board of Trustee  */
    2: /* version 4.6 */
    3: 
    4: /* Jan 28  1997  I.T. */
    5: /* July 23 1998  I.T. */
    6: 
    7: #ifdef NeXT
    8: #include <stdlib.h>
    9: #include <objc/zone.h>
   10: #include <mach/mach.h>
   11: #else
   12: #include <malloc.h>
   13: double atof();
   14: #endif
   15: 
   16: #include <ctype.h>
   17: 
   18: #ifdef TRUE
   19: #undef TRUE
   20: #endif
   21: #ifdef FALSE
   22: #undef FALSE
   23: #endif
   24: 
   25: #include <curses.h>
   26: 
   27: #if defined(__alpha) || defined(linux) 
   28: 
   29: #ifdef LOGIN_DBUG
   30: 
   31: #define NO_PIN
   32: #define NO_DATE_CHECK
   33: #define NO_DUP_CHECK
   34: 
   35: #endif
   36: 
   37: #include <curses.h>
   38: #else
   39: #if defined(__sun) || defined(hpux) || defined(AIX) || defined(IRIX)
   40: #include <curses.h>  /* #include <stdio.h> */
   41: #include <math.h>   /* MAXFLOAT */
   42: 
   43: #else
   44: 
   45: #include <bsd/curses.h>
   46: 
   47: #endif
   48: #endif
   49: 
   50: #include <signal.h>
   51: #include <time.h>
   52: #include <math.h>
   53: #include <string.h>
   54: #include <unistd.h>
   55: #include "capaToken.h"
   56: #include "capaParser.h"
   57: #include "capaCommon.h"
   58: 
   59: FILE      *dfp;
   60: 
   61: #define   TERM_SUMMARY    1
   62: #define   EXAM_SUMMARY    2
   63: #define   QUIZ_SUMMARY    3
   64: 
   65: #define   TRY_BOUND       99
   66: 
   67: 
   68: 
   69: 
   70: #define   TYR_SET_MENU_MACRO(xxx)   {					\
   71:  sprintf(aLine,"Total %d problems", num_questions); \
   72:  if(xxx) { \
   73:   mvaddstr(20,1,"Enter command  M,  A,  #,  T, or  X.");           mvaddstr(20,67,"COMMAND:"); \
   74:   mvaddstr(21,1,"M=go to Main Menu  A=Answer    T=Time   RETURN=execute command"); \
   75:  } else { \
   76:   mvaddstr(20,1,"Enter command  M,  #,  T,  or  X.    ");          mvaddstr(20,67,"COMMAND:"); \
   77:   mvaddstr(21,1,"M=go to Main Menu  T=Time               RETURN=execute command"); \
   78:  }  \
   79:  mvaddstr(22,1, "#=go to problem #  X=eXit CAPA"); \
   80:  mvaddstr(23,1,aLine); }
   81: 
   82: 
   83: #define   REVIEW_SET_MENU_MACRO()   {					\
   84:  sprintf(aLine,"Total %d problems", num_questions); \
   85:  mvaddstr(20,1,"Enter command  M,  #,  or  X.");              mvaddstr(20,67,"COMMAND:"); \
   86:  mvaddstr(21,1,"M=go to Main Menu                    RETURN=execute command"); \
   87:  mvaddstr(22,1,"#=go to problem #     X=eXit CAPA"); \
   88:  mvaddstr(23,1,aLine); } 
   89: 
   90: #define   TYRSET_MENU( )   {					\
   91:   mvaddstr(22,0,"Commands  :M = Main Menu   :7 = go to Problem 7            RETURN = Enter/Execute"); \
   92:  }
   93: 
   94: 
   95: #define   REVIEW_SET_MENU_MACRO()   {					\
   96:  sprintf(aLine,"Total %d problems", num_questions); \
   97:  mvaddstr(20,1,"Enter command  M,  #,  or  X.");              mvaddstr(20,67,"COMMAND:"); \
   98:  mvaddstr(21,1,"M=go to Main Menu                    RETURN=execute command"); \
   99:  mvaddstr(22,1,"#=go to problem #     X=eXit CAPA"); \
  100:  mvaddstr(23,1,aLine); } 
  101: 
  102: 
  103: #define DBUG_TSUMMARY    0
  104: 
  105: #define CLEAR()         clear(); refresh()
  106: #define ADDCH(c)        addch(c); refresh()
  107: #define CLRTOEOL()      clrtoeol(); refresh()
  108: #define CR 13
  109: #define LF 10
  110: #define SCREEN_BUFFER_SIZE   2048
  111: 
  112: time_t   log_in_time, log_out_time;
  113: char     in_t[32],    in_tty[32];
  114: char     Orig_path[FILE_NAME_LENGTH], Exam_path[FILE_NAME_LENGTH], 
  115:   Quiz_path[FILE_NAME_LENGTH];
  116: int      Exam_set, Quiz_set;
  117: int      g_inhibit_response;
  118: int      g_delay; /* delay when logging out */
  119: int      g_max_delay; /* max number of minutes to wait for input, kick_out()
  120:                          after this much time */
  121: /* Note: be careful to free entry answers */
  122: 
  123: /* ------------------------------------------------------------------------- */
  124: /* WRITE OUTPUT (NICELY) TO THE SCREEN                                       */
  125: /* ------------------------------------------------------------------------- */
  126: void              /* RETURNS: (nothing)         */
  127: wrap(str)         /* ARGUMENTS:                 */
  128: char *str;        /*    Block of text to output */
  129: {                 /* LOCAL VARIABLES:           */
  130:    int y,x,len;   /*    Row,Col of screen       */
  131:    int i,         /*    Next space              */
  132:        j;         /*    Next char to print      */
  133:   len=strlen(str);
  134:   for (i=j=0; i<len; i++) {
  135:     getyx(stdscr,y,x); 
  136:     while (i<len && !isspace(str[i]))    i++;
  137:     if (x+i-j > 78)  addch('\n');
  138:     while (j<=i)     addch(str[j++]);
  139:   }
  140: }
  141: int
  142: total_lines(char *str)
  143: {
  144:   int  len,  lines_cnt=1;
  145:   int  i, j, x=0;
  146:   
  147:   len=strlen(str);
  148:   for(i=j=0;i<len;i++) {
  149:     while (i<len && !isspace(str[i]))    i++;
  150:     if (x+i-j > 78)  { lines_cnt++; x = 0; }
  151:     while (j<=i)     { x++; if(str[j] == '\n') {lines_cnt++; x=0; }  j++; }
  152:   }
  153:   return (lines_cnt);
  154: }
  155: 
  156: /* --------------------------------------------- */
  157: /* */
  158: #define    LINES_PER_SCREEN     20
  159: 
  160: int  display_prob_scr(char *str,int scr_idx)
  161: {
  162:   int  len, lines_cnt=0;
  163:   int  i,j,y=0,x=0;
  164:   int  break_pt, onscreen_pr;
  165:   int  second_scr=0;
  166: 
  167:   if( str != NULL ) {
  168:     lines_cnt = total_lines(str);
  169:     if( lines_cnt > LINES_PER_SCREEN ) {
  170:       second_scr = 1;
  171:     } else {
  172:       scr_idx = 1;
  173:     }
  174:     if( scr_idx == 1 ) {
  175:       break_pt = LINES_PER_SCREEN + 1;
  176:     } else { /* which line to break the problem text into two screens */
  177:       if(lines_cnt>=40) { break_pt = LINES_PER_SCREEN; } else {
  178:         if(lines_cnt==39) { break_pt = LINES_PER_SCREEN - 1; } else {
  179:           if(lines_cnt==38) { break_pt = LINES_PER_SCREEN - 2; } else {
  180:             break_pt = LINES_PER_SCREEN - 3;
  181:           }
  182:         }
  183:       }
  184:     }
  185: 
  186: #ifdef LOGIN_DBUG
  187:    fprintf(dfp,"DISPLAY SCR IDX=%d total LineCnt=%d Line Break= %d:\n",scr_idx,lines_cnt,break_pt); fflush(dfp);
  188: #endif
  189: 
  190:   /*  start to display the text on screen */
  191: 
  192:     lines_cnt = 1; x = y =0;
  193:     len=strlen(str);
  194: #ifdef LOGIN_DBUG
  195:   fprintf(dfp,"SCR IDX=%d,leng=%d[[\n",scr_idx,len);
  196:   fflush(dfp);
  197: #endif  
  198:     for(i=j=0;i<len;i++) {
  199:       if( ( (scr_idx==1) && (lines_cnt < break_pt)) ||
  200:           ((scr_idx==2) && (lines_cnt > break_pt) && (lines_cnt <= (break_pt+LINES_PER_SCREEN))) ) {
  201:         getyx(stdscr,y,x);
  202: 	/*	if (x2>=x) x=x2; else x=x2+80;*/
  203:       }
  204:       while (i<len && !isspace(str[i]))    i++;
  205:       onscreen_pr = 0;
  206: #ifdef LOGIN_DBUG         
  207:       fprintf(dfp,"\n[NewWord line=%d,x=%d,i=%d,j=%d,y=%d]",lines_cnt,x,i,j,y);
  208: #endif         
  209:       if (x+i-j > 78)  { /* line break  */
  210:          if( (scr_idx==1) && (lines_cnt < break_pt) ) {
  211:            addch('\n'); onscreen_pr = 1;
  212: #ifdef LOGIN_DBUG         
  213:            fprintf(dfp,"\n[LineCnt=%d,x=%d,i=%d,j=%d]",lines_cnt,x,i,j);
  214: #endif         
  215:          }
  216:          if( (scr_idx==2) && (lines_cnt > break_pt) && (lines_cnt <= (break_pt+LINES_PER_SCREEN)) ) {
  217:          
  218:            addch('\n'); onscreen_pr = 1;
  219: #ifdef LOGIN_DBUG         
  220:            fprintf(dfp,"\n[LineCnt=%d,x=%d,i=%d,j=%d]",lines_cnt,x,i,j);
  221: #endif         
  222:          }
  223:          lines_cnt++;
  224:          if(onscreen_pr == 0 ) {
  225:            x=0;
  226:          }
  227:       }
  228:       while (j<=i)     { /* display on screen */
  229:          onscreen_pr = 0;
  230:          if( (scr_idx==1) && (lines_cnt < break_pt) ) {
  231:            addch(str[j]);   /* display that character */
  232:            onscreen_pr = 1;
  233: #ifdef LOGIN_DBUG            
  234:            fprintf(dfp,"%c",str[j]);
  235: #endif 
  236:          } 
  237:          if( (scr_idx==2) && (lines_cnt > break_pt) && (lines_cnt <= (break_pt+LINES_PER_SCREEN)) ) {
  238: 
  239:            addch(str[j]); onscreen_pr = 1;
  240: #ifdef LOGIN_DBUG            
  241:            fprintf(dfp,"%c",str[j]);
  242: #endif 
  243:          }
  244:          if( str[j] == '\n' )  {
  245:           
  246: #ifdef LOGIN_DBUG         
  247:          fprintf(dfp,"<LineCnt=%d>[j=%d]",lines_cnt,j);
  248: #endif
  249:            if(onscreen_pr == 0 ) {
  250:              x = 0;
  251:            }
  252:            lines_cnt++; 
  253:          }
  254:          if(onscreen_pr == 0 ) {
  255:            x++;
  256:          }
  257:          j++;
  258:        }
  259:     }
  260: #ifdef LOGIN_DBUG
  261:   fprintf(dfp,"\n]]"); fflush(dfp);
  262: #endif
  263: 
  264:   }
  265:   return (second_scr);
  266: 
  267: }
  268: 
  269: /* ------------------------------------------------------------------------- */
  270: /* DISPLAY FAREWELL MESSAGE WHEN USER GOT KICKED OUT                         */
  271: /* ------------------------------------------------------------------------- */
  272: void               /* RETURNS: (nothing)      */
  273: #ifdef __sun
  274: kick_out(int sig)
  275: #else
  276: kick_out()
  277: #endif
  278: 
  279: {                  /* LOCAL VARIABLES:        */
  280:    FILE *fp;       /*    Goodbye file pointer */
  281:    char  buf[255]; /*    Input buffer         */
  282: 
  283:    /* DISPLAY EXIT MESSAGE */
  284:    CLEAR();
  285:    if ((fp=fopen("goodbye.msg","r"))!=NULL) {
  286:       while (fgets(buf,255,fp))
  287:          addstr(buf);
  288:       fclose(fp);
  289:    }
  290:    sprintf(buf, "This message will last for only %d seconds.",g_delay);
  291:    mvaddstr(22,20,buf); refresh();
  292:    sleep(g_delay);
  293:    /* mypause(22,20); */
  294: 
  295:    /* CURSES RESTORATION */
  296:    resetty(); endwin();
  297:    exit(1);
  298: }
  299: 
  300: 
  301: /* ------------------------------------------------------------------------- */
  302: /* GET INPUT (NICELY) FROM A PLACE ON THE SCREEN                             */
  303: /* ------------------------------------------------------------------------- */
  304: void                     /* RETURNS: (nothing)             */
  305: get_input(y,x,str,inmax) /* ARGUMENTS:                     */
  306: int   y,x;               /*   Row,Col of screen to start   */
  307: char *str;               /*   String buffer to fill in     */
  308: int   inmax;             /*   Maximum number of characters */
  309: {                        /* LOCAL VARIABLES:               */
  310:    int  i=0,cx,cy;       /*   Position in buffer           */
  311:    char c;               /*   Input character              */
  312:    
  313:    if (y && x)  move(y,x);
  314:    CLRTOEOL();
  315:    cx = x; cy = y;
  316: #if defined( __alpha) || defined(__sun)
  317:    while (1) {
  318:       alarm(g_max_delay*60);
  319:       c=getch();
  320:       if (c==10 || c==13)   break;
  321:       else if (c==8 || c==16 || c==127) {
  322:          if (i>0) {
  323:             i--;  cx--;  echo(); move(cy,cx);
  324:             delch();  insch(' '); refresh(); noecho();
  325:          } else
  326:          beep();
  327:       } else if (i>=inmax) { beep(); } else {
  328:          str[i++] = c; cx++;
  329:          echo(); ADDCH(c); noecho();
  330:       }
  331:    }
  332: #else  
  333:    while (1) {
  334:       alarm(g_max_delay*60);
  335:       c=getch();
  336:       if (c==10 || c==13) break;
  337:       else if (c==8 || c==16 || c==127) {
  338:          if (i>0) {
  339:             i--;  printf("%c %c",8,8); refresh();
  340:          } else   printf("%c",7);
  341:       } else if (i>=inmax) { printf("%c",7);
  342:       } else {
  343:          str[i++] = c;  ADDCH(c);
  344:       }
  345:    }
  346: #endif
  347:    str[i]=0;
  348: }
  349: 
  350: 
  351: void                     /* RETURNS: (nothing)             */
  352: get_xinput(y,x,str,inmax)/* ARGUMENTS:                     */
  353: int   y,x;               /*   Row,Col of screen to start   */
  354: char *str;               /*   String buffer to fill in     */
  355: int   inmax;             /*   Maximum number of characters */
  356: {                        /* LOCAL VARIABLES:               */
  357:    int  i=0,cx,cy;       /*   Position in buffer           */
  358:    char c;               /*   Input character              */
  359: 
  360:    
  361:    for(i=0;i<inmax;i++) { move(y,x+i); ADDCH(' '); }
  362:    i=0;
  363:    if (y && x)  move(y,x);refresh();
  364:    cx = x; cy = y;
  365: #if defined( __alpha) || defined(__sun)
  366:    while (1) {      
  367:      alarm(g_max_delay*60);
  368:      c=getch();
  369:      if (c==10 || c==13)   break;
  370:      else if (c==8 || c==16 || c==127) {
  371:        if (i>0) {
  372: 	 i--;  cx--;  echo(); move(cy,cx);
  373: 	 delch();  insch(' '); refresh(); noecho();
  374:        } else
  375:          beep();
  376:      } else if (i>=inmax) { beep(); } else {
  377:        str[i++] = c; cx++;
  378:        echo(); ADDCH(c); noecho();
  379:      }
  380:    }
  381: #else  
  382:    while (1) {
  383:      alarm(g_max_delay*60);
  384:      c=getch();
  385:      if (c==10 || c==13) break;
  386:      else if (c==8 || c==16 || c==127) {
  387:        if (i>0) {
  388: 	 i--;  printf("%c %c",8,8); refresh();
  389:        } else   printf("%c",7);
  390:      } else if (i>=inmax) { printf("%c",7);
  391:      } else {
  392:        str[i++] = c;  ADDCH(c);
  393:      }
  394:    }
  395: #endif
  396:    str[i]=0;
  397: }
  398: 
  399: /*
  400: void                     
  401: input_pin(y,x,str,inmax) 
  402: int   y,x;               
  403: char *str;               
  404: int   inmax;             
  405: {                        
  406:    int  i=0,cx,cy;       
  407:    char c;               
  408: 
  409:    if (y && x)  move(y,x);
  410:    cx = x; cy = y;
  411:    CLRTOEOL();
  412: #ifdef __alpha
  413:    while (1) {
  414:       c=getch();
  415:       if (c==10 || c==13)   break;
  416:       else if (c==8 || c==16 || c==127) {
  417:          if (i>0) {
  418:             i--;  cx--;  echo(); move(cy,cx);
  419:             delch();  insch(' '); refresh(); noecho();
  420:          } else
  421:          beep();
  422:       } else if (i>=inmax) { beep(); } else {
  423:          str[i++] = c; cx++;
  424:          echo(); ADDCH('*'); noecho();
  425:       }
  426:    }
  427: #else  
  428:    while (1) {
  429:       c=getch();
  430:       if (c==10 || c==13) break;
  431:       else if (c==8 || c==16 || c==127) {
  432:          if (i>0) {
  433:             i--;  printf("%c %c",8,8); refresh();
  434:          } else   printf("%c",7);
  435:       } else if (i>=inmax) { printf("%c",7);
  436:       } else {
  437:          str[i++] = c;  ADDCH('*');
  438:       }
  439:    }
  440: #endif
  441:    str[i]=0;
  442: }
  443: */
  444: 
  445: /* ------------------------------------------------------------------------- */
  446: /* PAUSE UNTIL USER HITS A KEY                                               */
  447: /* ------------------------------------------------------------------------- */
  448: void         /* RETURNS: (nothing)   */
  449: mypause(y,x) /* ARGUMENTS:           */
  450: int y,x;     /*    Row,Col of screen */
  451: {            /* LOCAL VARIABLES:     */
  452:    char c;   /*    Input character   */
  453: 
  454:    mvaddstr(y,x,"Press ENTER/RETURN to continue");
  455:    get_input(y,x+30,&c,0);
  456: }
  457: 
  458: /* ------------------------------------------------------------------------- */
  459: /* DISPLAY FAREWELL MESSAGE WHEN USER LOGS OUT                               */
  460: /* ------------------------------------------------------------------------- */
  461: void               /* RETURNS: (nothing)      */
  462: properly_logout(student_number)       /* ARGUMENTS:      */
  463: char *student_number;
  464: {                  /* LOCAL VARIABLES:        */
  465:    FILE  *fp;       /*    Goodbye file pointer */
  466:    char   buf[255]; /*    Input buffer         */
  467:    char  *out_t;
  468:    char   filename[FILE_NAME_LENGTH];
  469:    
  470:    /* DISPLAY EXIT MESSAGE */
  471:    CLEAR();
  472:    time(&log_out_time);
  473:    out_t=ctime(&log_out_time);
  474:    out_t[ strlen(out_t)-1 ]=0; /* Trash newline */
  475: 
  476:    sprintf(filename,"records/duration.db");
  477:    if ((fp=fopen(filename,"a"))==NULL) {
  478:       printf("Error: can't open duration file\n");
  479:       return; 
  480:    }
  481:    flockstream(fp);
  482:    fprintf(fp,"%s\t%s\t%s\t%s\n",student_number,in_tty,in_t,out_t);
  483:    funlockstream(fp);
  484:    fclose(fp);
  485: 
  486: 
  487:    if ((fp=fopen("goodbye.msg","r"))!=NULL) {
  488:       while (fgets(buf,255,fp))
  489:          addstr(buf);
  490:       fclose(fp);
  491:    }
  492:    /* mypause(22,20); */
  493: #ifndef NO_DUP_CHECK
  494:    logout_check(student_number);
  495: #endif
  496: 
  497: #ifndef LOGIN_DBUG
  498:    sprintf(buf, "This message will last for only %d seconds.",g_delay);
  499:    mvaddstr(22,20,buf); refresh();
  500:    sleep(g_delay);
  501: #endif
  502: 
  503:    /* CURSES RESTORATION */
  504:    resetty(); endwin();
  505:    exit(1);
  506: }
  507: /* ------------------------------------------------------------------------- */
  508: /* Forbid duplicate login                                                    */
  509: /* ------------------------------------------------------------------------- */
  510: void               /* RETURNS: (nothing)      */
  511: dup_login_out()       /* ARGUMENTS:                */
  512: {                  /* LOCAL VARIABLES:        */
  513:    FILE *fp;       /*    Goodbye file pointer */
  514:    char  buf[255]; /*    Input buffer         */
  515: 
  516:    /* DISPLAY EXIT MESSAGE */
  517:    CLEAR();
  518:    if ((fp=fopen("third-login.msg","r"))!=NULL) {
  519:       while (fgets(buf,255,fp))   addstr(buf);
  520:       fclose(fp);
  521:    }
  522:    /* mypause(22,20);*/
  523:    /* CURSES RESTORATION */
  524:    sprintf(buf, "This message will last for only %d seconds.",g_delay);
  525:    mvaddstr(22,20,buf); refresh();
  526:    sleep(g_delay);
  527:    resetty(); endwin();
  528:    exit(1);
  529: }
  530: 
  531: void               /* RETURNS: (nothing)      */
  532: dup_login_warning()/* ARGUMENTS:              */
  533: {                  /* LOCAL VARIABLES:        */
  534:    FILE *fp;       /*    Welcome file pointer */
  535:    char  buf[255]; /*    Input buffer         */
  536: 
  537:    CLEAR();
  538:    if ((fp=fopen("second-login.msg","r"))!=NULL) {
  539:       while (fgets(buf,255,fp))
  540:          addstr(buf);
  541:       fclose(fp);
  542:    }
  543:    mypause(22,20);
  544: }
  545: 
  546: /* ------------------------------------------------------------------------- */
  547: /* ALLOW USER TO LOG IN                                                      */
  548: /* ------------------------------------------------------------------------- */
  549: char                          /* RETURNS: Student number                     */
  550: *login(maxset,section)        /* ARGUMENTS:                                  */
  551: int *maxset;                  /*    Set number                               */
  552: int *section;                 /*    Section number                           */
  553: {                             /* LOCAL VARIABLES:                            */
  554:    char    *student_number;   /*    Student number                           */
  555:    int      guess,            /*    User-entered PIN                         */
  556:             login_set;        /*    Set for which PIN is valid               */
  557:    int      login_section = 0;
  558:    char     buff[20];         /*    Input buffer                             */ 
  559:    T_entry  entry;
  560:    time_t   curtime;          /*    Current time                             */
  561:    int      leng;
  562:    T_student student_data;
  563: 
  564: #define    D_S_NUM_Y    11
  565: #define    D_S_NUM_X    13
  566: 
  567: #define    D_PIN_Y      (D_S_NUM_Y + 2)
  568: #define    D_PIN_X      (D_S_NUM_X + 10)
  569: #define    D_EXIT_Y     (D_S_NUM_Y + 5)
  570: #define    D_EXIT_X     (D_S_NUM_X + 6)
  571: #define    IN_S_NUM_Y   (D_S_NUM_Y)
  572: #define    IN_S_NUM_X   (D_S_NUM_X + 16)
  573: #define    IN_PIN_Y     (D_PIN_Y)
  574: #define    IN_PIN_X     (D_PIN_X + 9)
  575: #define    M_INVALID_Y  (IN_PIN_Y + 1)
  576: #define    M_INVALID_X  (IN_PIN_X)
  577: 
  578:    student_number = (char *)malloc( (MAX_STUDENT_NUMBER+4)*sizeof(char));
  579:    /* LOOP UNTIL WE ARE LEGALLY LOGGED IN */
  580:    do {
  581:       mvaddstr(D_S_NUM_Y,D_S_NUM_X,"STUDENT NUMBER: ");
  582:       mvaddstr(D_PIN_Y,D_PIN_X,"CAPA ID: ");
  583:       mvaddstr(D_EXIT_Y,D_EXIT_X,"To exit system, just hit ENTER/RETURN");
  584: 
  585: #ifndef  NO_PIN
  586:       /* LOOP UNTIL WE HAVE A STUDENT NUMBER AND PIN */
  587:       do {
  588: #endif  /* NO_PIN */
  589: 
  590:          /* LOOP UNTIL A LEGAL STUDENT NUMBER IS ENTERED */
  591:          do {
  592:             get_input(IN_S_NUM_Y,IN_S_NUM_X,buff, MAX_STUDENT_NUMBER);
  593: #ifdef __sun
  594:             if (!strlen(buff))    kick_out(0);
  595: #else
  596:             if (!strlen(buff))    kick_out();
  597: #endif
  598:             sscanf(buff,"%s",student_number); leng = strlen(student_number);
  599:          } while (leng < MAX_STUDENT_NUMBER);
  600: 
  601: #ifndef  NO_PIN
  602:          get_input(IN_PIN_Y,IN_PIN_X,buff,MAX_PIN_CHAR);
  603: #ifdef __sun
  604:          if (!strlen(buff))       kick_out(0);
  605: #else
  606:          if (!strlen(buff))       kick_out();
  607: #endif
  608:          sscanf(buff,"%d",&guess);
  609:       } while (guess<1);
  610: #endif   /* NO_PIN */
  611: 
  612:       student_number[strlen(student_number)] = 0;
  613:       /* VERIFY PIN */
  614: 
  615: #ifdef  NO_PIN
  616: login_set = 1;
  617: #else 
  618: login_set = capa_PIN(student_number,999,guess);
  619: #endif  /* No_PIN */
  620:       
  621: #ifdef LOGIN_DBUG
  622:   fprintf(dfp,"LOGIN:S=%s,Guess=%04d,Actual Pin=%04d,set=%d\n",
  623:    student_number,guess,capa_PIN(student_number,1, 0), login_set);
  624:   fprintf(dfp," PIN=%04d,%04d,%04d,%04d,%04d\n",
  625:    capa_PIN(student_number,1, 0), capa_PIN(student_number,2, 0),capa_PIN(student_number,3, 0),
  626:    capa_PIN(student_number,4, 0), capa_PIN(student_number,5, 0));
  627:   fflush(dfp);
  628: #endif
  629:       if (!login_set) {
  630:          mvaddstr(M_INVALID_Y,M_INVALID_X,   "INVALID LOGIN  ");
  631:       } else {
  632:          if ( login_set > 99 )  {
  633:            mvaddstr(M_INVALID_Y,M_INVALID_X, "INCORRECT PIN  ");  login_set = 0;
  634:          }
  635:          if ( capa_get_student(student_number,&student_data) == 0 ) {
  636:             mvaddstr(M_INVALID_Y,M_INVALID_X,"NO SUCH STUDENT");  login_set=0;
  637:          } else {
  638:             login_section = student_data.s_sec;
  639: #ifdef LOGIN_DBUG
  640:   fprintf(dfp, " Student in section %d\n",login_section);fflush(dfp);
  641: #endif
  642:             time(&curtime);
  643:             if( capa_check_date(CHECK_OPEN_DATE,student_number,
  644: 				login_section,login_set) < 0 ) {
  645:                mvaddstr(M_INVALID_Y,M_INVALID_X,"NOT YET OPEN!");  login_set=0;
  646:             }
  647:          }
  648:       }
  649:     } while ( !login_set );
  650: #ifdef LOGIN_DBUG
  651:   fprintf(dfp, "DEBUG:%s Access granted through set %d section %d\n",
  652:     student_number, login_set, login_section);  fflush(dfp);
  653: #endif
  654: #ifndef NO_DUP_CHECK
  655:     switch( login_check(student_number))  {
  656:       case 0:
  657:          mvaddstr(M_INVALID_Y,M_INVALID_X,"CANNOT LOGIN");  dup_login_out();
  658:          break;
  659:       case 1:
  660:          mvaddstr(M_INVALID_Y,M_INVALID_X,"FIRST TIME LOGIN");
  661:          break;
  662:       case 2:
  663:          mvaddstr(M_INVALID_Y,M_INVALID_X,"SECOND TIME LOGIN"); dup_login_warning( );
  664:          break;
  665:       case -1:
  666: #ifdef __sun
  667:         mvaddstr(M_INVALID_Y,M_INVALID_X,"FILE ERROR"); kick_out(0);
  668: #else
  669:         mvaddstr(M_INVALID_Y,M_INVALID_X,"FILE ERROR"); kick_out();
  670: #endif
  671:          break;
  672:     }
  673: #endif /* NO_DUP_CHECK */
  674:    capa_get_entry(&entry,student_number,login_set);
  675:    (*maxset) = login_set;
  676:    (*section) = login_section;
  677:    capa_mfree(entry.answers);
  678:    capa_mfree(entry.tries);
  679:    return (student_number);
  680: }
  681: 
  682: /* ------------------------------------------------------------------------- */
  683: /* LOG ANSWERS TO A FILE WITH TIMESTAMP                                      */
  684: /* ------------------------------------------------------------------------- */
  685: int                                                /* RETURNS: error code    */
  686: log_attempt(student_number,set,section,log_string) /* ARGUMENTS:             */
  687: char     student_number[MAX_STUDENT_NUMBER+1];     /*   Student number       */
  688: int   set;                                         /*   Set number           */
  689: int   section;                                     /*   Section number       */
  690: char *log_string;                                  /*   Answer string to log */
  691: {                                                  /* LOCAL VARIABLES:       */
  692:    char   filename[FILE_NAME_LENGTH],              /*   Log filename buffer  */
  693:          *ct;                                      /*   Current time string  */
  694:    FILE  *fp;                                      /*   Log file pointer     */
  695:    time_t t;                                       /*   Timestamp for log    */
  696: 
  697:    /* OPEN LOG FILE */
  698: 
  699:    sprintf(filename,"records/log%d.db",set);
  700:    if ((fp=fopen(filename,"a"))==NULL) {
  701:       printf("Error: can't open log file\n");
  702:       return -1; 
  703:    }
  704: 
  705:    /* CREATE LOG ENTRY */
  706:    time(&t);
  707:    ct=ctime(&t);
  708:    ct[ strlen(ct)-1 ]=0; /* Trash newline */
  709:    fprintf(fp,"%s %s %s\n",student_number,ct,log_string); fflush(fp);
  710:    fclose(fp);
  711:    return 0;
  712: }
  713: 
  714: int  log_submissions(student_number,set,log_string)
  715: char  student_number[MAX_STUDENT_NUMBER+1];     
  716: int   set;  
  717: char *log_string;                                
  718: {                                                  
  719:    char   filename[FILE_NAME_LENGTH], timeStr[FILE_NAME_LENGTH],buf2[MAX_BUFFER_SIZE];
  720:    FILE  *fp;                                     
  721:    time_t t;            
  722:    struct tm     *tmtime;
  723:    int do_log_submissions=1,result;
  724:    char buf[MAX_BUFFER_SIZE];
  725: 
  726:    result=read_capa_config("do_log_submissions",buf);
  727:    if (result != 0 && result != -1) {
  728:      if (strcasecmp(buf2,"no")==0) {
  729:        do_log_submissions=0;
  730:      } 
  731:    }
  732:    if (!do_log_submissions) return 0;
  733: 
  734:    sprintf(filename,"records/submissions%d.db",set);
  735:    if ((fp=fopen(filename,"a"))==NULL) {
  736:      return (-1);
  737:    }
  738: 
  739:    /* CREATE LOG ENTRY */
  740:    time(&t);
  741:    tmtime=localtime(&t);
  742:    strftime(timeStr,FILE_NAME_LENGTH,"%d/%m %X",tmtime);
  743:    /*ct[ strlen(ct)-1 ]=0;*/ /* Trash newline */
  744:    protect_log_string(log_string);
  745:    fprintf(fp,"%s\t%s\t%s\n",student_number,timeStr,log_string); fflush(fp);
  746:    fclose(fp);
  747:    return (0);
  748: }
  749: 
  750: #define   C_FORWARD    1
  751: #define   C_EXIT       2
  752: #define   C_MENU       3
  753: #define   C_HINT       4
  754: #define   C_EXPLAIN    5
  755: #define   C_ANSWER     6
  756: #define   C_JUMP       7
  757: #define   C_DONTCARE   8
  758: #define   C_BACKWARD   9
  759: #define   C_TIME       10
  760: #define   C_NEXTSCR    11
  761: #define   C_PREVSCR    12
  762: #define   C_SUBJANS    13
  763: 
  764: /* ------------------------------------------------------------------------- */
  765: /* DISPLAY SUMMARY OF SCORES FOR THE TERM                                    */
  766: /* ------------------------------------------------------------------------- */
  767: void                                     /* RETURNS: (nothing)          */
  768: term_summary(student_number,set,section,type) /* ARGUMENTS:             */
  769: char  *student_number;                   /*    Student Number           */
  770: int    set;                              /*    Set number               */
  771: int   *section;                          /*    Section Number           */
  772: int    type;
  773: {                                        /* LOCAL VARIABLES:            */
  774:    int      set_idx,                     /*    Set counter              */
  775:             i,                           /*    Question counter         */
  776:             tmp,                         /*    Question correct flag    */
  777:             set_score,                   /*    Score on a set           */
  778:             term_score=0,                /*    Total points received    */
  779:             term_total=0,                /*    Total points possible    */
  780:             result,
  781:             tot_num_sets=0;
  782:    T_entry  entry;                       /*    Database entry for a set */
  783:    char     buf[MAX_BUFFER_SIZE], buf2[MAX_BUFFER_SIZE];
  784:    T_header header;                      /*    Problem set header       */
  785:    int      topset=1,                    /*    First displayed set      */
  786:             bottomset,                   /*    Last displayed set       */
  787:             done=0,                      /*    Done flag                */
  788:             line, col;
  789:    int      probs_in_set[MAX_BUFFER_SIZE],/*    # problem set questions  */
  790:             start_at[MAX_BUFFER_SIZE],
  791:             valid_wgt[SMALL_LINE_BUFFER],
  792:             a_valid_wgt,set_start_line,
  793: 	    usr_command,inhibit_response;
  794: 
  795:    /* CALCULATE TERM TOTALS */
  796:   start_at[0] = -2;
  797:   probs_in_set[0]= 0;
  798:   for (set_idx=1; set_idx<=set; set_idx++) {
  799:     if (capa_get_header(&header,set_idx))  return;
  800:     if ( capa_check_date(CHECK_OPEN_DATE,student_number,*section,set_idx) < 0 ) 
  801:       continue;
  802:     tot_num_sets++;
  803:     capa_get_entry(&entry,student_number,set_idx);
  804:     sscanf(header.num_questions,"%d", &(probs_in_set[set_idx]) );
  805:     start_at[set_idx] = start_at[set_idx-1]+2*(1+probs_in_set[set_idx-1]/50);
  806:     if ((start_at[set_idx]%12)+2*(1+probs_in_set[set_idx]/50) > 12)
  807:          start_at[set_idx] = 12*(1+start_at[set_idx]/12);
  808:     valid_wgt[set_idx] = 0;
  809:     for (i=0; i<probs_in_set[set_idx]; i++) {
  810:       valid_wgt[set_idx] +=  (header.weight[i] - '0');
  811:       if((entry.answers[i]=='Y') || (entry.answers[i]=='y'))  
  812: 	term_score += (header.weight[i]-'0');
  813:       if((entry.answers[i]=='E') || (entry.answers[i]=='e'))  
  814: 	valid_wgt[set_idx] -= (header.weight[i] - '0');
  815:       if((entry.answers[i]>='0') && (entry.answers[i]<='9'))  
  816: 	term_score += (entry.answers[i] - '0');
  817:     }
  818:     term_total += valid_wgt[set_idx];
  819:     capa_mfree(header.weight);
  820:     capa_mfree(header.partial_credit);
  821:     capa_mfree(entry.answers);
  822:     capa_mfree(entry.tries);
  823:   }
  824: 
  825:    /* FIND TOPSET */
  826:    line = 12*(start_at[set]/12);      /* Top line # of last screen */
  827:    for (topset=set; topset>1 && start_at[topset-1]>=line; topset--);
  828: 
  829:    /* SHOW HEADER */
  830:    CLEAR();
  831:    switch(type) {
  832:      case TERM_SUMMARY:    mvaddstr(1,30,"TERM SUMMARY"); break;
  833:      case EXAM_SUMMARY:    mvaddstr(1,30,"EXAM SUMMARY"); break;
  834:      case QUIZ_SUMMARY:    mvaddstr(1,30,"QUIZ SUMMARY"); break;
  835:    }
  836:    mvaddstr(3,22,"         1         2         3         4         5");
  837:    mvaddstr(4,22,"12345678901234567890123456789012345678901234567890");
  838: 
  839:    /* DISPLAY COMMAND MENU */
  840:    mvaddstr(21,1,"Enter a command from the list below and press ENTER/RETURN    COMMAND:");
  841:    mvaddstr(22,1,"M =Go to main menu  N =Next Page  P =Prev Page");
  842:    /* mvaddstr(22,1,"X =eXit M =Go to main menu  N =Next Page  P =Prev Page"); */
  843:    refresh();
  844: 
  845:    /* SHOW TOTALS */
  846:    /* if capalogin_show_summary_score is set to none don't show it */
  847:    if (term_total > 0 ) {
  848:      sprintf(buf,"%d sets, total=%3d/%3d (%d%%)", tot_num_sets, term_score, term_total,
  849: 	     100*term_score/term_total);
  850:    } else {
  851:      sprintf(buf,"%d sets, total=%3d/%3d", tot_num_sets, term_score, term_total);
  852:    }
  853:    result=read_capa_config("capalogin_show_summary_score",buf2);
  854:    if (result != 0 && result != -1) {
  855:      if (strcasecmp(buf2,"none")==0) {
  856:      } else {
  857:        mvaddstr(19,1,buf);
  858:      }
  859:    } else {
  860:      mvaddstr(19,1,buf);
  861:    }
  862: 
  863:    /* LOOP UNTIL DONE */
  864:   while (!done) {
  865:     /* PRINT 1 LINE SUMMARY PER SET */
  866:     line=5;
  867:     for (set_idx=topset; set_idx<=set; set_idx++) {
  868:       /* don't show summary for set if inhibit response is set*/
  869:       inhibit_response=capa_check_option(OPTION_INHIBIT_RESPONSE,set_idx,*section);
  870:       if (inhibit_response > 0) continue;
  871:       if ( capa_check_date(CHECK_OPEN_DATE,student_number,*section,set_idx) < 0 ) 
  872: 	continue;
  873:       set_score=0;
  874:       set_start_line=line;
  875:     /* Stop if not enough lines to summarize set */
  876:       if (line+2*(probs_in_set[set_idx]/50)>16)   break;
  877:       capa_get_header(&header,set_idx);
  878:       capa_get_entry(&entry,student_number,set_idx);
  879:       a_valid_wgt = 0;
  880:        for (i=0, col=0; i<probs_in_set[set_idx]; i++) {
  881:          tmp=0; a_valid_wgt += (header.weight[i] - '0');
  882:          move(line,  22+col); addch(entry.answers[i]);
  883:          move(line+1,22+col); addch(header.weight[i]);
  884:          switch(entry.answers[i]) {
  885:            case 'Y': tmp=header.weight[i] -'0'; break; /* Answer correct */
  886:            case 'y': tmp=header.weight[i] -'0'; break; /* Grading correct */
  887:            case '-': break;        /* Not answered    */
  888:            case 'N': break;        /* Answer incorrect */
  889:            case 'n': break;        /* Grading incorrect */
  890:            case 'e': a_valid_wgt -= (header.weight[i] - '0'); break;  /* Excuse    */
  891:            case 'E': a_valid_wgt -= (header.weight[i] - '0'); break;  /* Excuse    */
  892:            default : if( entry.answers[i] >= '0' && entry.answers[i] <= '9' ) {
  893:                        tmp = entry.answers[i] - '0';
  894:                      }
  895:                      break;
  896:          }
  897:          set_score  += tmp; col++;
  898:          if (!((i+1)%50)) { line += 2; col = 0; }
  899:        }
  900:        capa_mfree(header.weight);
  901:        capa_mfree(header.partial_credit);
  902:        capa_mfree(entry.answers);
  903:        capa_mfree(entry.tries);
  904:        move(line, 22+col);   CLRTOEOL();
  905:        move(line+1, 22+col); CLRTOEOL();
  906:        if(a_valid_wgt == 0) {
  907:          set_score=0;
  908:          sprintf(buf,"%3d:%3d/%3d(%3d%%)  ",set_idx,set_score,a_valid_wgt,set_score);
  909:          mvaddstr(set_start_line,1,buf);
  910:        } else {
  911:          sprintf(buf,"%3d:%3d/%3d(%3d%%)  ",set_idx,set_score,a_valid_wgt,100*set_score/a_valid_wgt);
  912:          mvaddstr(set_start_line,1,buf);
  913:        }
  914:        line += 2;
  915:     }
  916:     bottomset=set_idx-1;
  917: 
  918:       /* Blank out any extra lines */
  919:     if (line < 16) {
  920:      for (set_idx=line; set_idx<=16; set_idx++) {
  921:        move(set_idx,1);
  922:        CLRTOEOL();
  923:      }
  924:     }
  925: 
  926:       /* PROCESS USER COMMAND */
  927:       get_input(21,72,buf,1);
  928:       if(!strlen(buf)) { usr_command = C_FORWARD; } else {
  929:         
  930:           switch(toupper(buf[0])) {
  931:            /* case 'X': usr_command=C_EXIT;    break; */
  932:            case 'M': usr_command=C_MENU;    break;
  933: 	   case 'P': usr_command=C_BACKWARD; break;
  934:            default : usr_command=C_FORWARD;    break;
  935:           }
  936:       }
  937: 
  938:       
  939:       switch(usr_command) {
  940:       case C_DONTCARE: break;
  941:       case C_FORWARD: /* Forwards */
  942:                 if (bottomset<set) { topset=bottomset+1; } else { done=1; }
  943:                 break;
  944:       
  945:       case C_BACKWARD: /* Backwards */
  946:                 if (topset<2) break;
  947:                 line = 12*(start_at[topset-1]/12); /* Top line # of prev screen */
  948:                 for (; topset>1 && start_at[topset-1]>=line; topset--);
  949:                 break;
  950: 
  951:       case C_MENU: /* Menu */
  952:                 done=1;
  953:                 break;
  954:       case C_EXIT: /* Exit */
  955:                 properly_logout(student_number);
  956:                 break;
  957:       default:  /* Invalid command */
  958:                 break;
  959:       }
  960:    }
  961: }
  962: 
  963: void
  964: display_hint(char *h)
  965: {
  966: 
  967:   CLEAR();
  968: 
  969:   wrap(h);
  970:   mypause(22,20);
  971: }
  972: 
  973: #define   A_ROW    20
  974: #define   S_ROW    21
  975: #define   O_ROW    22
  976: #define   X_ROW    23
  977: 
  978: #define   A_COL    14
  979: #define   S_COL    46
  980: #define   H_COL    24
  981: #define   E_COL    39
  982: #define   X_COL    8
  983: #define   R_COL    57
  984: #define   U_ANS_CHAR  32
  985: 
  986: /* =============================================================================
  987: 0001234567890123456789012345678901234567890123456789012345678901234567890123456789
  988: A
  989: S1OPTION/ANSWER 12345678901234 -----            *Unanswered
  990: O2Options :M = Main Menu  :7 = go to #7  :N = Next screen  RETURN = Enter/Execute
  991: X3        :X = eXit       :H = Show Hint :E = Explain      RETURN = Next Problem
  992:   0123456789012345678901234567890123456789012345678901234567890
  993:           ^     ^         ^              ^      ^          ^
  994:           X     A         H              E      S          R
  995: */
  996: int  show_prior_response(Problem_t *p,int hgr,int prev_ans,int tried,int *allow_h)
  997: {
  998:   char     *c_answer_str, tmp_str[MAX_BUFFER_SIZE];
  999:   char     *response="Incorrect",*answered="Answered";
 1000:   int       can_answer;
 1001:   
 1002:   if( hgr == '0' || p->ans_type==ANSWER_IS_SUBJECTIVE) {
 1003:     switch(prev_ans) {
 1004:       case 'Y': can_answer=NAY; *allow_h=1;
 1005:                 c_answer_str = answers_string(ANSWER_STRING_MODE,p);
 1006:                 move(A_ROW,A_COL); clrtoeol();  
 1007:                 mvaddstr(A_ROW,A_COL,c_answer_str); capa_mfree(c_answer_str);
 1008:                 move(S_ROW,S_COL); clrtoeol();
 1009:                 mvaddstr(S_ROW,S_COL,"**Correct              "); break;
 1010:       case 'y': can_answer=NAY; *allow_h=1;
 1011:                 c_answer_str = answers_string(ANSWER_STRING_MODE,p);
 1012:                 move(A_ROW,A_COL); clrtoeol();
 1013:                 mvaddstr(A_ROW,A_COL,c_answer_str); capa_mfree(c_answer_str);
 1014:                 move(S_ROW,S_COL); clrtoeol();
 1015:                 mvaddstr(S_ROW,S_COL,"*Hand-graded Correct      "); break;
 1016:       case '-': can_answer=YAK; move(S_ROW,S_COL); clrtoeol();
 1017:                 mvaddstr(S_ROW,S_COL,"*Unanswered               "); break;
 1018:       case 'E': can_answer=NAY; move(S_ROW,S_COL); clrtoeol();
 1019:                 mvaddstr(S_ROW,S_COL,"*Excused                  "); break;
 1020:       case 'e': can_answer=NAY; move(S_ROW,S_COL); clrtoeol();
 1021:                 mvaddstr(S_ROW,S_COL,"*Excused                  "); break;
 1022:       case 'n': can_answer=NAY; move(S_ROW,S_COL); clrtoeol();
 1023:                 mvaddstr(S_ROW,S_COL,"*Hand-graded Incorrect    "); break;
 1024:     case '0': case '1': case '2': case '3': case '4': case '5': 
 1025:     case '6': case '7': case '8': case '9':
 1026:       response=answered;
 1027:     case 'N':   if ( tried < p->tries ) {
 1028:                   can_answer=YAK;
 1029: 		  if( (p->tries - tried) == 1 ) {
 1030: 		    sprintf(tmp_str,"*%s, ONE try left!!",response);
 1031: 		  } else {
 1032: 		    sprintf(tmp_str,"*%s, tries %2d/%2d   ",response,tried,p->tries);
 1033: 		  }
 1034:                 } else {
 1035: 		  can_answer=NAY;
 1036: 		  sprintf(tmp_str,  "*%s, no more tries",response);
 1037: 		}
 1038:                 move(S_ROW,S_COL); clrtoeol();
 1039:                 mvaddstr(S_ROW,S_COL,tmp_str); 
 1040:                 if( (can_answer == YAK) && (p->ans_op == ANS_AND) && (p->ans_cnt > 1)) {
 1041:                    sprintf(tmp_str, " Entering answer   1 of %3d     ",p->ans_cnt);
 1042:                    mvaddstr(A_ROW,S_COL,tmp_str);
 1043:                 }
 1044:                 break;
 1045:     }
 1046:   } else {  /* hand graded question */
 1047:     can_answer=NAY;
 1048:     move(S_ROW,S_COL); clrtoeol();
 1049:     mvaddstr(S_ROW,S_COL,"*Hand-graded question     ");
 1050:   }
 1051:   /* ------------------------------------------------------------------ */
 1052:   if (*allow_h && 
 1053:       p->hint && 
 1054:       (
 1055:        ( p->show_hint <= tried ) || 
 1056:        ( prev_ans == 'y' ) ||
 1057:        ( prev_ans == 'Y' )
 1058:        )
 1059:       ) {
 1060:     mvaddstr(X_ROW,H_COL,":H = Show Hint");
 1061:   } else {
 1062:     *allow_h = 0;
 1063:   }
 1064:   if (p->next)
 1065:     mvaddstr(X_ROW,R_COL,"RETURN = Next Problem");
 1066:   else
 1067:     mvaddstr(X_ROW,R_COL,"RETURN = Main Menu   ");
 1068:   
 1069:   return (can_answer);
 1070:   
 1071: }
 1072: int  show_prior_inhibited_response(Problem_t *p,int hgr,int prev_ans,int tried,
 1073: 				   int *allow_h)
 1074: {
 1075:   char     tmp_str[MAX_BUFFER_SIZE];
 1076:   int      can_answer;
 1077:   
 1078:   if( hgr == '0' ) {
 1079:     switch(prev_ans) {
 1080:       case '-': can_answer=YAK; move(S_ROW,S_COL); clrtoeol();
 1081:                 mvaddstr(S_ROW,S_COL,"*Unanswered               "); break;
 1082:       case 'E':
 1083:       case 'e':
 1084:       case 'n':
 1085:       case 'y': 
 1086:       case 'Y': 
 1087:       case 'N': if ( tried < p->tries ) {
 1088: 	          can_answer=YAK;
 1089: 		  if( (p->tries - tried) == 1 ) {
 1090: 		    sprintf(tmp_str,"*Answered, ONE try left!! ");
 1091: 		  } else {
 1092: 		    sprintf(tmp_str,"*Answered, tries %2d/%2d    ",tried,p->tries);
 1093: 		  }
 1094:                 } else {
 1095: 		  can_answer=NAY;
 1096: 		  sprintf(tmp_str,  "*Answered, no more tries ");
 1097: 		}
 1098:                 move(S_ROW,S_COL); clrtoeol();
 1099:                 mvaddstr(S_ROW,S_COL,tmp_str); break;
 1100:            
 1101:     }
 1102:   } else {  /* hand graded question */
 1103:     can_answer=NAY;
 1104:     move(S_ROW,S_COL); clrtoeol();
 1105:     mvaddstr(S_ROW,S_COL,"*Hand-graded question     ");
 1106:   }
 1107:   /* ------------------------------------------------------------------ */
 1108:   if (*allow_h && p->hint && ( p->show_hint <= tried)){
 1109:     mvaddstr(X_ROW,H_COL,":H = Show Hint");
 1110:   } else {
 1111:     *allow_h = 0;
 1112:   }
 1113:   if (p->next)
 1114:     mvaddstr(X_ROW,R_COL,"RETURN = Next Problem");
 1115:   else
 1116:     mvaddstr(X_ROW,R_COL,"RETURN = Main Menu   ");
 1117:   
 1118:   return (can_answer);
 1119:   
 1120: }
 1121: /* -------------------------------------------- dbug --------------------- */
 1122: void
 1123: print_unit_components(FILE *fp,Unit_t *t) 
 1124: {
 1125:   Unit_E  *ue_p;
 1126: 
 1127:   fprintf(fp,"  Unit::[%s] = %g * ", t->u_symbol, t->u_scale);
 1128:   for(ue_p=t->u_list; ue_p ; ue_p = ue_p->ue_nextp) {
 1129:     fprintf(fp,"(%g*%s^%g) ",ue_p->ue_scale,ue_p->ue_symbol,ue_p->ue_exp);
 1130:   }
 1131:   fprintf(fp,"\n"); fflush(fp);
 1132: 
 1133: }
 1134: 
 1135: 
 1136: /*#define    ANSWER_STRING_LENG       64*/
 1137: #define    UNIT_STRING_LENG         64
 1138: #define    FORMAT_STRING_LENG       32
 1139: 
 1140: /* ------------------------------------------------------------------- */
 1141: int  give_response(Problem_t *p,char **a,int cnt,int *tried,int *log_char)
 1142: {
 1143:   int      can_answer;
 1144:   char     tmp_str[MAX_BUFFER_SIZE], *c_answer_str;
 1145:   char    *error=NULL;
 1146: 
 1147:   switch( capa_check_answers(p,a,cnt,&error) ) {
 1148: 
 1149:     case  EXACT_ANS:  move(A_ROW,S_COL); clrtoeol();
 1150:                       mvaddstr(A_ROW,S_COL,"*Yes Computer gets:"); 
 1151:                       c_answer_str = answers_string(ANSWER_STRING_MODE, p);
 1152:                       move(S_ROW,S_COL); clrtoeol();
 1153:                       mvaddstr(S_ROW,S_COL,c_answer_str);
 1154:                       capa_mfree((char *)c_answer_str);
 1155:                      *log_char='Y'; can_answer=NAY;
 1156:                       if( *tried < TRY_BOUND)  (*tried)++;
 1157:                       break;
 1158:     case  APPROX_ANS: 
 1159:                       move(A_ROW,S_COL); clrtoeol();
 1160:                       mvaddstr(A_ROW,S_COL,"*Yes Computer gets:");
 1161:                       c_answer_str = answers_string(ANSWER_STRING_MODE, p);
 1162:                       if(cnt == 1 ) {
 1163:                         move(S_ROW,S_COL); clrtoeol();
 1164:                         mvaddstr(S_ROW,S_COL,c_answer_str);
 1165:                       } else {  /* more than one answer to check ANS_AND */
 1166:                         move(S_ROW,S_COL); clrtoeol();
 1167:                         mvaddstr(S_ROW,S_COL,"*Yes Correct Answers See Above");
 1168:                         move(A_ROW,A_COL); clrtoeol();
 1169:                         mvaddstr(A_ROW,A_COL,c_answer_str);
 1170:                       }
 1171:                       capa_mfree((char *)c_answer_str);
 1172:                      *log_char='Y'; can_answer=NAY;
 1173:                       if(*tried < TRY_BOUND)  (*tried)++;
 1174:                       break;
 1175:     case  WANTED_NUMERIC:   move(S_ROW,S_COL); clrtoeol();  
 1176:                       mvaddstr(S_ROW,S_COL,"*Enter a Number Ans");
 1177:                      *log_char='S'; can_answer=YAK;
 1178:                       break;
 1179:     case  SIG_FAIL:   move(S_ROW,S_COL); clrtoeol();  
 1180:                       mvaddstr(S_ROW,S_COL,"*Adjust Sig. Figs. ");
 1181:                      *log_char='S'; can_answer=YAK;
 1182: 		      capa_mfree(error);
 1183:                       break;
 1184:     case  UNIT_FAIL:  move(S_ROW,S_COL); clrtoeol();  
 1185:                       mvaddstr(S_ROW,S_COL,"*Units incorrect   ");
 1186:                      *log_char='U'; can_answer=YAK;
 1187: 		      capa_mfree(error);
 1188:                       break;
 1189:     case  UNIT_NOTNEEDED:  move(S_ROW,S_COL); clrtoeol();  
 1190:                       mvaddstr(S_ROW,S_COL,"*Only a number required");
 1191:                      *log_char='U'; can_answer=YAK;
 1192: 		      capa_mfree(error);
 1193:                       break;
 1194:     case  NO_UNIT:    move(S_ROW,S_COL); clrtoeol();  
 1195:                       mvaddstr(S_ROW,S_COL,"*Units required    ");
 1196:                      *log_char='u'; can_answer=YAK;
 1197:                       break;
 1198:     case  BAD_FORMULA:move(S_ROW,S_COL); clrtoeol();  
 1199:                       mvaddstr(S_ROW,S_COL,"*Unable to interpret formula");
 1200:                      *log_char='F'; can_answer=YAK;
 1201:                       break;
 1202:     case  ANS_CNT_NOT_MATCH:
 1203:                       move(S_ROW,S_COL); clrtoeol();  
 1204:                       mvaddstr(S_ROW,S_COL,"*Invalid number of answers");
 1205:                      *log_char='C'; can_answer=YAK;
 1206:                       break;
 1207:     case  INCORRECT: 
 1208:                       if(*tried < TRY_BOUND)  (*tried)++;
 1209: 		      if ( *tried < p->tries ) {
 1210: 			can_answer=YAK;
 1211: 			if( (p->tries - *tried) == 1 ) {
 1212: 			  sprintf(tmp_str,"*Incorrect, ONE try left!!");
 1213: 			} else {
 1214: 			  sprintf(tmp_str,"*Incorrect, tries %2d/%2d   ",*tried,p->tries);
 1215: 			}
 1216: 		      } else {
 1217: 			can_answer=NAY;
 1218: 			sprintf(tmp_str,  "*Incorrect, no more tries");
 1219: 		      }
 1220:                       move(S_ROW,S_COL); clrtoeol(); 
 1221:                       mvaddstr(S_ROW,S_COL, tmp_str);
 1222:                       if( (can_answer == YAK) && (p->ans_op == ANS_AND) && (p->ans_cnt > 1)  ) {
 1223:                          sprintf(tmp_str, " Entering answer   1 of %3d     ",p->ans_cnt);
 1224:                          mvaddstr(A_ROW,S_COL,tmp_str);
 1225:                       }
 1226: 	             *log_char='N';
 1227: 	              break;
 1228:   }
 1229:    
 1230:   return (can_answer);
 1231: }
 1232: 
 1233: int  give_inhibited_response(Problem_t *p,char **a,int cnt,int *tried,int *log_char)
 1234: {
 1235:   int      can_answer;
 1236:   char     tmp_str[MAX_BUFFER_SIZE];
 1237:   char    *error=NULL;
 1238: 
 1239:   switch( capa_check_answers(p,a,cnt,&error) ) {
 1240: 
 1241: 
 1242:     case  EXACT_ANS:  *log_char='Y'; break;
 1243:     case  APPROX_ANS: *log_char='Y'; break;
 1244:     case  SIG_FAIL:   *log_char='S'; capa_mfree(error); break;
 1245:     case  UNIT_FAIL:  *log_char='U'; capa_mfree(error); break;
 1246:     case  UNIT_NOTNEEDED: *log_char='U'; capa_mfree(error); break;
 1247:     case  NO_UNIT:    *log_char='u'; break;
 1248:     case  BAD_FORMULA:*log_char='F'; break;
 1249:     case  INCORRECT:  *log_char='N'; break;
 1250:     case  WANTED_NUMERIC:  *log_char='s'; break;
 1251:     case ANS_CNT_NOT_MATCH: *log_char='C'; break;
 1252:   }
 1253:   
 1254:   if(*tried < TRY_BOUND)  (*tried)++;
 1255:   if ( *tried < p->tries ) {
 1256:     can_answer=YAK;
 1257:     if( (p->tries - *tried) == 1 ) {
 1258:       sprintf(tmp_str,"*Answered, ONE try left!! ");
 1259:     } else {
 1260:       sprintf(tmp_str,"*Answered, tries %2d/%2d    ",*tried,p->tries);
 1261:     }
 1262:   } else {
 1263:     can_answer=NAY;
 1264:     sprintf(tmp_str,  "*Answered, no more tries ");
 1265:   }
 1266:   move(S_ROW,S_COL); clrtoeol(); 
 1267:   mvaddstr(S_ROW,S_COL, tmp_str);
 1268:   return (can_answer);
 1269: }
 1270: 
 1271: int  ask_what_prob(int q_cnt, char *ans)
 1272: {
 1273:   int  not_ok=1,num,anslength,i,j;
 1274:   char buf[5],buf2[MAX_BUFFER_SIZE];
 1275:   
 1276:   move(14,35); clrtoeol();
 1277:   move(17,5);  clrtoeol();
 1278:   do {
 1279:      move(14,35); clrtoeol();
 1280:      move(15,0);  clrtoeol();
 1281:      mvaddstr(15,13,"What problem number:");
 1282:      move(17,0);  clrtoeol();
 1283:      mvaddstr(17,16,"         1         2         3         4         5");
 1284:      mvaddstr(18,16,"12345678901234567890123456789012345678901234567890");
 1285:      anslength=strlen(ans);
 1286:      for(i=0;i<=(anslength/50);i++) {
 1287:        if ( g_inhibit_response ) {
 1288: 	 for(j=50*i;(j<((i+1)*50))&&(j<anslength);j++) {
 1289: 	   if (ans[j]=='-') 
 1290: 	     buf2[j-(50*i)]='-';
 1291: 	   else
 1292: 	     buf2[j-(50*i)]='A';
 1293: 	 }
 1294: 	 buf2[j-(50*i)]='\0';
 1295:        } else {
 1296: 	 strncpy(buf2,&(ans[50*i]),50);
 1297:        }
 1298:        buf2[50]='\0';
 1299:        mvaddstr(19+i,16,buf2);
 1300:        if (anslength > 50 ) {
 1301: 	 sprintf(buf2,"%3d-%3d",i*50+1,(i+1)*50);
 1302: 	 mvaddstr(19+i,5,buf2);
 1303:        }
 1304:      }
 1305:      do { get_input(15,34,buf,4); } while(!strlen(buf));
 1306:      sscanf(buf,"%d",&num);
 1307:      if (num<1 || num>q_cnt) {
 1308:         move(21,5); clrtoeol();
 1309:         mvaddstr(21,15,"  Error: Invalid problem number\n");
 1310:      } else {
 1311:         not_ok = 0;
 1312:      }
 1313:   } while (not_ok);
 1314: 
 1315:   return (num);
 1316: }
 1317: 
 1318: /* gather subjective answers from student */
 1319: 
 1320: #define    BS    8
 1321: #define    DEL   127
 1322: #define    ESC   27
 1323: 
 1324: #define    COLON 58
 1325: 
 1326: #define EDIT_HEIGHT 21
 1327: #define EDIT_WIDTH 80
 1328: #define MENULINE EDIT_HEIGHT
 1329: 
 1330: void refresh_editor (char **sbuf_pp,int cx,int cy) {
 1331:   int i;
 1332:   CLEAR();
 1333:   echo();
 1334:   mvaddstr(MENULINE,0,"Type in the answer, use up, down, left, right keys to move curser");
 1335:   mvaddstr(MENULINE+1,0,"Enter ctrl-e to exit and submit answer");
 1336:   mvaddstr(MENULINE+2,0,"Enter ctrl-f to forget answer");
 1337:   for(i=0;i<EDIT_HEIGHT;i++) { mvaddstr(i,0,sbuf_pp[i]); }
 1338:   move(cy,cx); refresh(); noecho();
 1339: }
 1340: 
 1341: void init_editor(char*** sbuf_pp)
 1342: {
 1343:   int   ww=EDIT_WIDTH, hh=EDIT_HEIGHT,i;
 1344:   *sbuf_pp = (char **)capa_malloc(sizeof(char *),hh);
 1345:   for(i=0;i<hh;i++) {
 1346:     (*sbuf_pp)[i] = (char *)capa_malloc(sizeof(char)*ww+1,1);
 1347:   }
 1348:   CLEAR();echo();
 1349:   mvaddstr(MENULINE,0,"Type in the answer, use up, down, left, right keys to move cursor");
 1350:   mvaddstr(MENULINE+1,0,"Enter ctrl-e to exit and submit answer");
 1351:   mvaddstr(MENULINE+2,0,"Enter ctrl-f to forget answer");
 1352:   move(0,0); refresh(); noecho();
 1353: }
 1354: 
 1355: void remove_character(char** sbuf_pp,int *cx,int *cy)
 1356: {
 1357:   int sx=(*cx)-1,sy=*cy;
 1358:   char temp,*temp_p;
 1359:   if (*cx==0) { 
 1360:     int abovelen,curlen,diff,i,j;
 1361:     if (*cy==0) { beep();return;}
 1362:     abovelen=strlen(sbuf_pp[(*cy-1)]);
 1363:     curlen=strlen(sbuf_pp[*cy]);
 1364:     if (abovelen > 0) sbuf_pp[(*cy)-1][abovelen-1]='\0';
 1365:     if ((abovelen+curlen) < EDIT_WIDTH) {
 1366:       strcat(sbuf_pp[(*cy)-1],sbuf_pp[*cy]);
 1367:       memset(sbuf_pp[(*cy)],'\0',EDIT_WIDTH+1);
 1368:       temp_p=sbuf_pp[*cy];
 1369:       i=*cy;
 1370:       while(i<EDIT_HEIGHT-1) {
 1371: 	sbuf_pp[i]=sbuf_pp[i+1];
 1372: 	echo();move(i,0);CLRTOEOL();mvaddstr(i,0,sbuf_pp[i]);noecho();
 1373: 	i++;
 1374:       }
 1375:       sbuf_pp[EDIT_HEIGHT-1]=temp_p;
 1376:       echo();move(EDIT_HEIGHT-1,0);CLRTOEOL();noecho();
 1377:     } else {
 1378:       diff=EDIT_WIDTH-abovelen;
 1379:       strncat(sbuf_pp[(*cy)-1],sbuf_pp[*cy],diff);
 1380:       i=diff;j=0;
 1381:       while(sbuf_pp[*cy][i]!='\0') {
 1382: 	sbuf_pp[*cy][j]=sbuf_pp[*cy][i];
 1383: 	i++;j++;
 1384:       }
 1385:       memset(&(sbuf_pp[(*cy)][j]),'\0',EDIT_WIDTH+1-j);
 1386:     }
 1387:     echo();move(*cy,0); CLRTOEOL(); mvaddstr(*cy,0,sbuf_pp[*cy]);noecho();
 1388:     (*cy)--;
 1389:     echo();move(*cy,0); CLRTOEOL(); mvaddstr(*cy,0,sbuf_pp[*cy]);noecho();
 1390:     if ( EDIT_WIDTH == ((*cx)=(abovelen-1))) (*cx)--;
 1391:     if (abovelen==0) *cx=0;
 1392:     echo();move(*cy,*cx);noecho();
 1393:   } else {
 1394:     echo();move(sy,sx);noecho();
 1395:     temp=sbuf_pp[sy][sx]=sbuf_pp[sy][sx+1];
 1396:     sx++;
 1397:     while(temp!='\0') {
 1398:       echo(); ADDCH(temp); noecho();
 1399:       temp=sbuf_pp[sy][sx]=sbuf_pp[sy][sx+1];
 1400:       sx++;
 1401:     }
 1402:     echo(); ADDCH(' '); noecho();
 1403:     (*cx)--;
 1404:   }
 1405:   echo();move(*cy,*cx);noecho();
 1406: }
 1407: 
 1408: void break_line      (char** sbuf_pp,int *cx,int *cy)
 1409: {
 1410:   int sx=*cx,sy=*cy,i;
 1411:   if (sy < EDIT_HEIGHT-1) {
 1412:     capa_mfree(sbuf_pp[EDIT_HEIGHT-1]);
 1413:     i=EDIT_HEIGHT-1;
 1414:     while (i-1 > sy) {
 1415:       sbuf_pp[i]=sbuf_pp[i-1];
 1416:       move(i,0);CLRTOEOL();mvaddstr(i,0,sbuf_pp[i]);
 1417:       i--;
 1418:     }
 1419:     sbuf_pp[sy+1]=capa_malloc(sizeof(char)*EDIT_WIDTH+1,1);
 1420:   }
 1421:   strcat(sbuf_pp[sy+1],&(sbuf_pp[sy][sx]));
 1422:   memset(&(sbuf_pp[sy][sx]),'\0',EDIT_WIDTH+1-sx);
 1423:   *cx=0;
 1424:   (*cy)++;
 1425:   move(sy,0);CLRTOEOL();mvaddstr(sy,0,sbuf_pp[sy]);
 1426:   move(sy+1,0);CLRTOEOL();mvaddstr(sy+1,0,sbuf_pp[sy+1]);
 1427: }
 1428: 
 1429: /* FIXME catch funtion keys and others? */
 1430: void handle_esc      (unsigned char ca,unsigned char cb,char** sbuf_pp,int *cx,int *cy)
 1431: {
 1432:   if( ca!='[') return;
 1433:   switch (cb) {
 1434:   case 'A':/* KEY_UP */
 1435:     if(*cy>0){
 1436:       (*cy)--;
 1437:       while(*cx>0 && sbuf_pp[*cy][(*cx)-1]=='\0') (*cx)--; /* goto end of line */
 1438:     } else {
 1439:       beep();
 1440:     }
 1441:     break;
 1442:   case 'B': /* KEY_DOWN */
 1443:     if (*cy<(EDIT_HEIGHT-1)) {
 1444:       (*cy)++;
 1445:       while(*cx>0 && sbuf_pp[*cy][(*cx)-1]=='\0') (*cx)--; /* goto end of line */
 1446:     } else {
 1447:       beep();
 1448:     }
 1449:     break;
 1450:   case 'C': /* KEY_RIGHT */
 1451:     if ( *cx<(EDIT_WIDTH-1) && sbuf_pp[*cy][(*cx)]!='\0' ) { 
 1452:       (*cx)++; 
 1453:     } else {
 1454:       if (*cy<(EDIT_HEIGHT-1)) {
 1455: 	(*cy)++; *cx=0; 
 1456:       } else {
 1457: 	beep();
 1458:       }
 1459:     }
 1460:     break;
 1461:   case 'D': /* KEY_LEFT */
 1462:     if(*cx>0) {
 1463:       (*cx)--;
 1464:     } else {
 1465:       if(*cy>0) { 
 1466: 	(*cy)--;
 1467: 	*cx=strlen(sbuf_pp[*cy]);
 1468: 	if (*cx==EDIT_WIDTH) (*cx)--;
 1469:       } else { 
 1470: 	beep(); 
 1471:       }
 1472:     }
 1473:     break;
 1474:   default: beep(); return; break;
 1475:   }
 1476:   echo(); move(*cy,*cx); refresh(); noecho();
 1477: }
 1478: 
 1479: void handle_error    (unsigned char c,char** sbuf_pp,int cx,int cy) 
 1480: {
 1481:   beep();
 1482: }
 1483: 
 1484: /*FIXME Slower than whale shit*/
 1485: void insert_character(unsigned char c,char** sbuf_pp,int *cx,int *cy) 
 1486: {
 1487:   int sx=*cx,sy=*cy;
 1488:   unsigned char temp;
 1489:   while(c!='\0') {
 1490:     if (sx == EDIT_WIDTH) {
 1491:       sx=0;sy++;
 1492:       if (sy == EDIT_HEIGHT) {
 1493: 	sy--;sx=EDIT_WIDTH;c='\0';break;
 1494:       }
 1495:     }	
 1496:     echo(); ADDCH(c); noecho();
 1497:     temp=sbuf_pp[sy][sx];
 1498:     sbuf_pp[sy][sx]=c;
 1499:     c=temp;
 1500:     sx++;
 1501:   }
 1502:   sbuf_pp[sy][sx]=c;
 1503:   (*cx)++;
 1504:   if (*cx == EDIT_WIDTH) {
 1505:       *cx=0;(*cy)++;
 1506:       if (*cy == EDIT_HEIGHT) {
 1507: 	(*cy)--;*cx=EDIT_WIDTH-1;
 1508:       }
 1509:   }
 1510:   move(*cy,*cx);refresh();
 1511: }
 1512: 
 1513: int handle_keystrokes_editor(char** sbuf_pp)
 1514: {
 1515:   int   done = 0, forget = 0, cx=0,cy=0;
 1516:   unsigned char c,ca,cb;
 1517: 
 1518:   while (!done) {
 1519:     move(cy,cx);refresh();
 1520:     c=getch();
 1521:     switch(c) {
 1522:     case BS: case DEL:
 1523:       remove_character(sbuf_pp,&cx,&cy);
 1524:       break;
 1525:     case CR: case LF:
 1526:       break_line(sbuf_pp,&cx,&cy);
 1527:       break;
 1528:     case ESC:
 1529:       ca=getch();cb=getch();
 1530:       handle_esc(ca,cb,sbuf_pp,&cx,&cy);
 1531:       break;
 1532:     case 5: /*ctrl-e*/
 1533:       done=1;
 1534:       break;
 1535:     case 6: /*ctrl-f*/
 1536:       done=1;
 1537:       forget=1;
 1538:       break;
 1539:     case 12:
 1540:       refresh_editor(sbuf_pp,cx,cy);
 1541:       break;
 1542:     default:
 1543:       if (c < 32 || c>126) {
 1544: 	handle_error(c,sbuf_pp,cx,cy);
 1545:       } else {
 1546: 	insert_character(c,sbuf_pp,&cx,&cy);
 1547:       }
 1548:       break;
 1549:     }
 1550:   }
 1551:   return forget;
 1552: }
 1553: 
 1554: int editor(char*** sbuf_pp)
 1555: {
 1556:   init_editor(sbuf_pp);
 1557:   return handle_keystrokes_editor(*sbuf_pp);
 1558: }
 1559: 
 1560: 
 1561: int
 1562: answer_subjective(student_number,set,section,prob)
 1563: char  *student_number; 
 1564: int    set; 
 1565: int   *section;
 1566: int    prob;
 1567: {
 1568:   int i,length;
 1569:   char date_str[DATE_LENGTH];
 1570:   char **sbuf_pp,answer[(EDIT_HEIGHT*(EDIT_WIDTH+1))+1];
 1571:   char submissions_str[(EDIT_HEIGHT*(EDIT_WIDTH+1))+MAX_BUFFER_SIZE];
 1572:   time_t     curtime;
 1573: 
 1574:   time(&curtime);
 1575:   if( capa_check_date(CHECK_DUE_DATE,student_number,*section,set) > 0 ) {
 1576:     capa_get_date(CHECK_DUE_DATE,student_number,*section,set,date_str);
 1577:     sprintf(answer,"Sorry, the due date was: %s",date_str);
 1578:     move(20,1); clrtobot(); addstr(answer); mypause(23,1);
 1579:     return 0;
 1580:   }
 1581: 
 1582:   if (editor(&sbuf_pp)) { return 0; }
 1583: 
 1584:   answer[0]='\0';
 1585:   for(i=0;i<EDIT_HEIGHT;i++) {
 1586:     if (strlen(sbuf_pp[i]) > 0) {
 1587:       strcat(answer,sbuf_pp[i]);
 1588:       length=strlen(answer);
 1589:       answer[length]='\n';
 1590:       answer[length+1]='\0';
 1591:     }
 1592:     capa_mfree((char *)sbuf_pp[i]);
 1593:   }
 1594:   capa_set_subjective(set,prob,student_number,answer);
 1595:   sprintf(submissions_str,"%d\t%s\t",prob,answer);
 1596:   log_submissions(student_number,set,submissions_str);
 1597:   capa_mfree((char *)sbuf_pp);
 1598:   return 1;
 1599: }
 1600: 
 1601: void set_entry_tries(int *tried, char *tries, int num, int num_questions) {
 1602:   if((tried[num] >=0) && (tried[num] <= TRY_BOUND) ) {
 1603:     if(tried[num] < 10 ) {
 1604:       tries[3*num]   = ' ';
 1605:       tries[3*num+1] = tried[num] + '0';
 1606:       if(num < num_questions-1)  tries[3*num+2] = ',';
 1607:     } else {
 1608:       tries[3*num]   = (int)(tried[num]/10) + '0';
 1609:       tries[3*num+1] = (tried[num] % 10) + '0';
 1610:       if(num < num_questions-1)  tries[3*num+2] = ',';
 1611:     }
 1612:   } else {
 1613:     tries[3*num]   = ' ';
 1614:     tries[3*num+1] = 1 + '0';
 1615:     if(num < num_questions-1)  tries[3*num+2] = ',';
 1616:   }
 1617: }
 1618: 
 1619: /* -------------------------------------------------------------------------- */
 1620: /* LET THE USER ANSWER THE CURRENT PROBLEM SET QUESTIONS                      */
 1621: /* -------------------------------------------------------------------------- */
 1622: void                                
 1623: try_set(student_number,set,section) 
 1624: char  *student_number; 
 1625: int    set; 
 1626: int   *section;
 1627: {
 1628:    char       a_student_number[MAX_STUDENT_NUMBER+1];
 1629:    time_t     curtime;
 1630:    T_header   header;
 1631:    Problem_t *first_problem, *p;
 1632:    T_entry    entry;
 1633:    char       answer[256], *a_str, **ans_strs;
 1634:    int        num, offset, num_questions, start_from, leng;
 1635:    char      *log_string,submissions_str[MAX_BUFFER_SIZE];
 1636:    int       *tried,answered;
 1637:    int        scr_idx=1, display=1, second_scr, canAnswer;
 1638:    int        usr_command, whereto, allow_hint=0, ex=0;
 1639:    char       u_input[64], date_str[DATE_LENGTH], one_line[81];
 1640:    int        log_char, i, j, allow_n, allow_p, allow_subj;
 1641:    
 1642:    strncpy(a_student_number,student_number,MAX_STUDENT_NUMBER+1);
 1643:    time(&curtime); /* Is due date past? */
 1644:    /* ---------------------------------------- check due date */
 1645: #ifndef NO_DATE_CHECK
 1646:    /* ===> if ( compare_datetime(curtime,header.due_date) > 0) { */
 1647:    if( capa_check_date(CHECK_DUE_DATE,student_number,*section,set) > 0 ) {
 1648:       capa_get_date(CHECK_DUE_DATE,student_number,*section,set,date_str);
 1649:       sprintf(answer,"  Sorry, the due date was: %s",date_str); 
 1650:       move(17,1); clrtoeol(); mvaddstr(17,15,answer);   mypause(19,17);
 1651:       return;
 1652:    }
 1653: #ifdef LOGIN_DBUG
 1654:   fprintf(dfp,"Tryset():(sec=%d,set=%d)[%s]\n",*section,set,date_str); fflush(dfp);
 1655: #endif /* LOGIN_DBUG */
 1656: #endif /* NO_DATE_CHECK */
 1657: 
 1658:    offset=capa_get_entry(&entry,student_number,set);
 1659:    capa_get_header(&header,set);
 1660:    if (offset<0) offset = -offset;  /* newly created entry */
 1661:    
 1662: #ifdef LOGIN_DBUG
 1663:    fprintf(dfp,"P set=%d,SN=%s,ANS=%s,TRY=%s\n",set,a_student_number,entry.answers,entry.tries); fflush(dfp);
 1664: #endif
 1665:    num = capa_parse(set,&first_problem,a_student_number,&num_questions,NULL);
 1666:    
 1667: #ifdef LOGIN_DBUG
 1668:   fprintf(dfp,"ParseSource:=%d\n",num); fflush(dfp);
 1669: #endif /* LOGIN_DBUG */
 1670: 
 1671:    /* DEBUGGING: make sure num_questions is plausible */
 1672:    if (num_questions>1000 || num_questions<=0)   properly_logout(student_number);
 1673:    
 1674:    start_from=ask_what_prob(num_questions,entry.answers);
 1675:    
 1676:    /* initialize log string to all '-' */
 1677:    tried = (int *)capa_malloc(num_questions+1,sizeof(int));
 1678:    log_string = (char *)capa_malloc(num_questions+1,sizeof(char));
 1679:    for (num=0; num<num_questions; num++)  {
 1680:      log_string[num]='-';
 1681:      sscanf(entry.tries + 3*num,"%d,",&(tried[num]) );
 1682:    }
 1683:    log_string[num_questions]=0;
 1684:    capa_set_login_time(student_number,set);
 1685:    for (num=0,p=first_problem; p; ){
 1686:       if( start_from > 1 ) {
 1687:         num=start_from-1;
 1688:         for (p=first_problem; start_from > 1 && p->next; start_from--)
 1689:              p=p->next;
 1690:         start_from = 0;
 1691:       }
 1692:       if (display) {
 1693:          /* DISPLAY QUESTION */
 1694:          CLEAR();
 1695:          second_scr = display_prob_scr(p->question,scr_idx);
 1696:          allow_subj = 0;
 1697:          if( p->ans_type == ANSWER_IS_SUBJECTIVE ) {
 1698:            allow_subj = 1;
 1699:            move(A_ROW,A_COL); clrtoeol();
 1700:            mvaddstr(A_ROW,A_COL,"Enter :A to answer subjective question");
 1701:          }
 1702:          mvaddstr(S_ROW,0,"OPTION/ANSWER");
 1703:          mvaddstr(O_ROW,0,"Options :M = Main Menu  :7 = go to # 7");
 1704:          allow_n = allow_p = 0;
 1705:          if( second_scr && (scr_idx == 1) ) {
 1706:            mvaddstr(O_ROW,E_COL,":N = Next screen");
 1707:            allow_n=1;
 1708:          }
 1709:          if( second_scr && (scr_idx == 2) ) {
 1710:            mvaddstr(O_ROW,E_COL,":P = Prev screen");
 1711:            allow_p=1;
 1712:          }
 1713:          
 1714:          mvaddstr(O_ROW,R_COL,"RETURN = Enter/Execute");
 1715: 	 
 1716: 	 if (g_inhibit_response ) {
 1717: 	   canAnswer = show_prior_inhibited_response(p,header.partial_credit[num],entry.answers[num],tried[num],&allow_hint);
 1718: 	 } else {
 1719: 	   canAnswer = show_prior_response(p,header.partial_credit[num],entry.answers[num],tried[num],&allow_hint);
 1720: 	 }
 1721: 	 
 1722:       }
 1723:       mvaddstr(X_ROW,X_COL,":X = eXit");
 1724:       
 1725:       /* <= */
 1726:       
 1727:       
 1728:       
 1729:         get_xinput(S_ROW,A_COL,u_input,U_ANS_CHAR);
 1730:         display=0;  usr_command=C_DONTCARE;
 1731:         /* DEFAULT ACTIONS on empty input */
 1732:         if(!strlen(u_input)) { usr_command = (p->next? C_FORWARD : C_MENU); } else {
 1733:           if( u_input[0] == ':' ) {
 1734:            switch(toupper( u_input[1] )) {
 1735:              case 'H': if( allow_hint ) { usr_command=C_HINT; } break;
 1736:              case 'M': usr_command=C_MENU;    break;
 1737:              case 'N': if( allow_n ) { usr_command=C_NEXTSCR; } break;
 1738:              case 'P': if( allow_p ) { usr_command=C_PREVSCR; } break;
 1739:              case 'X': usr_command=C_EXIT;    break;
 1740:              case 'A': if( allow_subj ) { usr_command=C_SUBJANS; } break;
 1741:              default : sscanf(u_input,":%d",&whereto);
 1742:                     if(whereto >0 && whereto <= num_questions) usr_command=C_JUMP;
 1743: 		    break;
 1744:            }
 1745:           } else { /* user entered some answer */
 1746:             if( p->ans_op == ANS_AND ) {
 1747:               if(canAnswer) { usr_command=C_ANSWER;
 1748:                 ans_strs = (char **)capa_malloc(sizeof(char *), p->ans_cnt);
 1749:                 ans_strs[0] = (char *)capa_malloc(strlen(u_input)+1,1);
 1750:                 strcpy(ans_strs[0],u_input);
 1751:                 for(i=1;i<p->ans_cnt;i++) {
 1752:                   mvaddstr(A_ROW,A_COL,"                                ");
 1753: 	          mvaddstr(A_ROW,A_COL,ans_strs[i-1]);
 1754:                   sprintf(one_line,    " Entering answer %3d of %3d     ", i+1,p->ans_cnt);
 1755:                   mvaddstr(A_ROW,S_COL,one_line);
 1756:                   mvaddstr(S_ROW,A_COL,"                                ");
 1757:                   get_xinput(S_ROW,A_COL,u_input,U_ANS_CHAR);
 1758:                   ans_strs[i] = (char *)capa_malloc(strlen(u_input)+1,1);
 1759:                   strcpy(ans_strs[i],u_input);
 1760:                   
 1761:                 }
 1762:                 
 1763:                 /* now in ans_strs[][] are user inputs */
 1764:                 
 1765:               }
 1766:             } else { /* one answer or ANS_OR */
 1767:               ans_strs = (char **)capa_malloc(sizeof(char *), 1);
 1768:               ans_strs[0] = (char *)capa_malloc(strlen(u_input)+1,1);
 1769:               strcpy(ans_strs[0], u_input);
 1770:               if(canAnswer)  { usr_command=C_ANSWER; 
 1771: 	         mvaddstr(S_ROW,A_COL,"                                ");
 1772: 	         mvaddstr(A_ROW,A_COL,"                                ");
 1773: 	         mvaddstr(A_ROW,A_COL,ans_strs[0]);  }
 1774: 	    }
 1775:           } /* end if  u_input[0] == ':' */
 1776:         } /* end if !strlen(u_input) */
 1777:       
 1778:         
 1779:       
 1780:       
 1781:       
 1782:       /* PROCESS USER COMMAND */
 1783:       switch(usr_command) {
 1784:         case C_FORWARD: /* Forwards */
 1785:                 if (p->next) {
 1786:                    p=p->next; num++;
 1787:                    display=1; allow_hint=0; scr_idx=1;
 1788:                 } else
 1789:                    mvaddstr(X_ROW,R_COL,"RETURN = Main Menu   ");
 1790:                 break;
 1791:         case C_NEXTSCR:  scr_idx = 2; display=1;
 1792:                 break;
 1793:         case C_PREVSCR:  scr_idx = 1; display=1;
 1794:                 break;
 1795:         case C_EXIT: /* Exit */ 
 1796:                 ex=1; p=0; break;
 1797:         case C_MENU: /* Return to main menu */
 1798:                 p=0;  break;
 1799:         case C_HINT: /* Hint */
 1800:                 if (! p->hint)    break;
 1801:                 display_hint(p->hint);
 1802:                 display=1;
 1803:                 break;
 1804:         case C_ANSWER: /* Answer question */
 1805:               { 
 1806: 		if(p->ans_type== ANSWER_IS_SUBJECTIVE) {
 1807: 		  move(A_ROW,A_COL); clrtoeol();
 1808: 		  mvaddstr(A_ROW,A_COL,"Enter :A to answer subjective question");
 1809: 		  capa_mfree(ans_strs[0]);
 1810: 		  break;
 1811: 		}
 1812: 		if( p->ans_op == ANS_AND ) {
 1813: 		    leng = 0;
 1814: 		    for(i=0;i<p->ans_cnt;i++) {
 1815: 		       leng += (strlen((char *)ans_strs[i]) + 2);
 1816: 		    }
 1817: 		    a_str = (char *)capa_malloc(leng+1,1);
 1818: 		    a_str[0]=0;
 1819: 		    strcat(a_str,ans_strs[0]);
 1820: 		    if ( is_all_ws(ans_strs[0]) )  break;
 1821: 		    trim_response_ws(ans_strs[0]);
 1822: 		    for(i=1;i<p->ans_cnt;i++) {
 1823: 		       strcat(a_str,"\t");
 1824: 		       strcat(a_str,ans_strs[i]);
 1825: 		       if ( is_all_ws(ans_strs[i]) )  break;
 1826: 		       trim_response_ws(ans_strs[i]);
 1827: 		    }
 1828: 		    if (i < p->ans_cnt) {
 1829: 		      display=1; /*handle early breaks out of the*/
 1830: 		      break; 	 /*loop which mean typed only ws */
 1831: 		    }
 1832: 		} else { /* only one answer */
 1833: 		  leng = (strlen((char *)ans_strs[0]) + 2);
 1834: 		  a_str = (char *)capa_malloc(leng+1,1);
 1835: 		  a_str[0]=0;
 1836: 		  strcat(a_str,ans_strs[0]);
 1837: 		  if ( is_all_ws(ans_strs[0]) )  break;
 1838: 		  trim_response_ws(ans_strs[0]);
 1839: 		}
 1840: 		
 1841: 		sprintf(submissions_str,"%d\t%s\t",num+1,a_str);
 1842: 		log_submissions(student_number,set,submissions_str);
 1843: 
 1844: 		{
 1845: 		  int cnt=((p->ans_op==ANS_AND)?p->ans_cnt:1);
 1846:      		  if (g_inhibit_response) {
 1847: 		    canAnswer = give_inhibited_response(p, ans_strs,cnt,
 1848: 							&(tried[num]),&log_char);
 1849: 		  } else {
 1850: 		    canAnswer = give_response(p, ans_strs,cnt, &(tried[num]),&log_char);
 1851: 		  }
 1852: 		}
 1853: 		if( p->ans_op == ANS_AND ) {
 1854: 		  for(i=0;i<p->ans_cnt;i++) {
 1855: 		    capa_mfree( (char *)ans_strs[i] );
 1856: 		  }
 1857: 		  
 1858: 		} else { /* there is only one user answer */
 1859: 		  capa_mfree( (char *)ans_strs[0] );
 1860: 		  
 1861: 		}
 1862: 		capa_mfree((char *)ans_strs);
 1863: 		capa_mfree( (char *)a_str );
 1864: 		
 1865:                 if (p->hint && 
 1866: 		    (
 1867: 		     (p->show_hint<=tried[num])||
 1868: 		     (log_char == 'y') ||
 1869: 		     (log_char == 'Y')
 1870: 		     )
 1871: 		    ){
 1872: 		  allow_hint=1;
 1873: 		  mvaddstr(X_ROW,H_COL,":H = Show Hint");
 1874:                 }
 1875:                 switch(log_char) {
 1876: 		  case 'U': case 'u': case 'S': case 'F':
 1877:                             entry.answers[num]='N';      break;
 1878:                   case 'Y': allow_hint=1; mvaddstr(X_ROW,H_COL,":H = Show Hint");  /* fall through here */
 1879:                    default: entry.answers[num]=log_char; break;
 1880:                 }
 1881:                 log_string[num]=log_char;
 1882:                 
 1883:                 log_attempt(student_number,set,*section,log_string);
 1884:                 /* for (i=0; i<num_questions; i++) { log_string[i] = '-' ;  } */
 1885: 		set_entry_tries(tried,entry.tries,num,num_questions);
 1886: 		log_string[num]='-';
 1887:                 /* ------------------------------ check due date */
 1888:                 time(&curtime);
 1889:                 /* ===> if (compare_datetime(curtime,header.due_date) > 0) { */
 1890:                 if( capa_check_date(CHECK_DUE_DATE,student_number,*section,set) > 0 ) {
 1891:                   capa_get_date(CHECK_DUE_DATE,student_number,*section,set,date_str);
 1892:                   sprintf(answer,"Sorry, the due date was: %s",date_str);
 1893:                   move(20,1); clrtobot(); addstr(answer); mypause(23,1);
 1894:                 } else {
 1895:                   capa_set_entry(&entry,student_number,set,offset);
 1896:                 }
 1897:               } break;
 1898:         case C_JUMP: /* Jump to specific question number */
 1899:                 num=whereto-1;
 1900:                 for (p=first_problem; whereto > 1 && p->next; whereto--)
 1901:                    p=p->next;
 1902:                 display=1;  allow_hint=0; scr_idx=1;
 1903:                 break;
 1904:         case C_SUBJANS:  
 1905:                 answered=answer_subjective(student_number,set,section,num+1); 
 1906: 		if (answered) {
 1907: 		  tried[num]++;
 1908: 		  if (p->hint && ((p->show_hint<=tried[num]))) { allow_hint=1; }
 1909: 		  entry.answers[num]='0';
 1910: 		  log_string[num]='A';
 1911: 		  log_attempt(student_number,set,*section,log_string);
 1912: 		  log_string[num]='-';
 1913: 		  set_entry_tries(tried,entry.tries,num,num_questions);
 1914:                   capa_set_entry(&entry,student_number,set,offset);
 1915: 		}
 1916:                 display=1;
 1917:                 break;
 1918:         case C_DONTCARE:  break;
 1919:       }
 1920:    }
 1921:    for (i=0,j=0, num=0; num<num_questions; num++) {
 1922:      j = j + (header.weight[num] - '0');
 1923:      if((entry.answers[num]=='Y') || (entry.answers[num]=='y')) 
 1924:        i = i + (header.weight[num] - '0');
 1925:      if( entry.answers[num] >= '0' && entry.answers[num] <= '9' ) {
 1926:         i = i + (entry.answers[num] - '0');
 1927:      }
 1928:      if((entry.answers[num]=='E') || (entry.answers[num]=='e')) 
 1929:        j = j - (header.weight[num] - '0');
 1930:      if((tried[num] >=0) && (tried[num] <= TRY_BOUND) ) {
 1931:        if(tried[num] < 10 ) {
 1932:          entry.tries[3*num]   = ' ';
 1933:          entry.tries[3*num+1] = tried[num] + '0';
 1934:          if(num < num_questions-1)  entry.tries[3*num+2] = ',';
 1935:        } else {
 1936:          entry.tries[3*num]   = (int)(tried[num]/10) + '0';
 1937:          entry.tries[3*num+1] = (tried[num] % 10) + '0';
 1938:          if(num < num_questions-1)  entry.tries[3*num+2] = ',';
 1939:        }
 1940:      } else {
 1941:        entry.tries[3*num]   = ' ';
 1942:        entry.tries[3*num+1] = 1 + '0';
 1943:        if(num < num_questions-1)  entry.tries[3*num+2] = ',';
 1944:      }
 1945:    }
 1946:    capa_mfree(header.weight);
 1947:    capa_mfree(header.partial_credit);
 1948: 
 1949:    sprintf(answer,"Your score for this set is now: %d/%d",i,j);
 1950:    move(20,1); clrtobot(); addstr(answer); mypause(23,1);
 1951:    /* ------- original code , should check due date before save it
 1952:    
 1953:    time(&curtime);
 1954:    if (compare_datetime(curtime,header.due_date) > 0) {
 1955:    if( capa_check_date(CHECK_DUE_DATE,*section,set) > 0 ) {
 1956:       need to deal with due_date 
 1957:       sprintf(answer,"Sorry, the due date was: %s",header.due_date);
 1958:       move(20,1); clrtobot(); addstr(answer); mypause(23,1);
 1959:    } else {
 1960:       sprintf(answer,"Your score for this set is now: %d/%d",i,j);
 1961:       move(20,1); clrtobot(); addstr(answer); mypause(23,1);
 1962:       
 1963:       capa_set_entry(&entry,student_number,set,offset);
 1964:    }
 1965:    ------ */
 1966:    /* FREE UP MALLOC'ED SPACE (VERY IMPORTANT) */
 1967:    capa_mfree(entry.answers);
 1968:    capa_mfree(entry.tries);
 1969:    free_problems(first_problem);
 1970:    /* log_attempt(student_number,set,*section,log_string); */
 1971:    capa_mfree(log_string);
 1972:    capa_mfree((char*)tried);
 1973:    if (ex) properly_logout(student_number);
 1974:    
 1975: }
 1976: 
 1977: #define   COL_ONE    1
 1978: #define   COL_TWO    17
 1979: #define   COL_THREE  34
 1980: #define   COL_FOUR   43
 1981: #define   COL_FIVE   69
 1982: 
 1983: /* ------------------------------------------------------------------------- */
 1984: /* REVIEW PREVIOUS PROBLEM SETS                                              */
 1985: /* ------------------------------------------------------------------------- */
 1986: void                                      /* RETURNS: (nothing)              */
 1987: view_previous(student_number,set,section) /* ARGUMENTS:                      */
 1988: char  *student_number;                    /*    Student number               */
 1989: int  set;                                 /*    Set number                   */
 1990: int *section;                             /*    Section number               */
 1991: {                                         /* LOCAL VARIABLES:                */
 1992:    T_entry   entry;                       /*    Database entry               */
 1993:    Problem_t *first_problem,              /*    Pointer to first problem     */
 1994:              *problem;                    /*    Previous problem             */
 1995:    int        num_questions,              /*    Total # of questions         */
 1996:               ex=0,                       /*    Exit system flag             */
 1997:               display=1,                  /*    Redraw flag                  */
 1998: 	      usr_command,
 1999: 	      whereto, 
 2000: 	      allow_hint=0, allow_explain=0;
 2001:    int        num;                        /*    Temporary variable           */
 2002:    char       buf[4],                     /*    Command input buffer         */
 2003:               aLine[MAX_BUFFER_SIZE];
 2004:    T_header   header;                     /*    Set header                   */
 2005:    time_t     curtime;                    /*    Current time                 */
 2006:    double     upper_ans;
 2007:    char       fmt_ans[ANSWER_STRING_LENG], goto_str[ANSWER_STRING_LENG], 
 2008:               tmp_str[ANSWER_STRING_LENG];
 2009:    int        scr_idx=1, second_scr, allow_n, allow_p;
 2010:    
 2011:    /* QUERY USER FOR SET */
 2012:    move(15,5);  /* deleteln(); */
 2013:    addstr("            Which set would you like to view?");
 2014:    mvaddstr(16,15,   "Enter a set number and press ENTER/RETURN");
 2015:    move(17,1); clrtoeol(); /* erase Enter a command ... */
 2016:    do { get_input(15,51,buf,3); } while(!strlen(buf));
 2017:    sscanf(buf,"%d",&num);
 2018:    if (num<1 || num>set) {
 2019:       move(17,5); clrtoeol();
 2020:       mvaddstr(17,15,"   Error: Invalid previous set number\n");
 2021:       mypause(19,17);   return;
 2022:    }
 2023:    /* ------------------------------------ answer date */
 2024:    time(&curtime);
 2025:    /* ===> if (compare_datetime(curtime,header.answer_date) < 0) { */
 2026:    if ( capa_check_date(CHECK_ANS_DATE,student_number,*section,num) < 0 ) {
 2027:       move(16,1); clrtoeol();
 2028:       move(17,5); clrtoeol();
 2029:       mvaddstr(17,15,"  Answers are not yet available\n");  mypause(19,17);  return;
 2030:    }
 2031: 
 2032:    /* LOAD IN THE INFO NEEDED */
 2033:    capa_get_header(&header,num);
 2034:    capa_get_entry(&entry,student_number,num);
 2035:    capa_parse(num,&first_problem,student_number,&num_questions,NULL);
 2036:    sprintf(goto_str,"#=go to problem #, [%d problems]", num_questions);
 2037:    for (num=0,problem=first_problem; problem; ) {
 2038:       if (display) {
 2039:          allow_hint = allow_explain=0;
 2040:          allow_n = allow_p = 0;
 2041:          CLEAR();
 2042:          second_scr = display_prob_scr(problem->question,scr_idx);
 2043:          if( problem->ans_type == ANSWER_IS_FLOAT ) {
 2044:              upper_ans = (double)atof(problem->answer);
 2045:              sprintf(fmt_ans, problem->ans_fmt, upper_ans);
 2046:          } else {
 2047:              sprintf(fmt_ans, "%s", problem->answer);
 2048:          }
 2049:          if( problem->ans_unit ) {
 2050:              sprintf(tmp_str, "Answer: %s %s",fmt_ans,problem->unit_str);
 2051:          } else {
 2052:              sprintf(tmp_str, "Answer: %s",fmt_ans);
 2053:          }
 2054:          mvaddstr(S_ROW,COL_ONE,tmp_str);
 2055:          
 2056:          switch(entry.answers[num]) {
 2057:            case 'Y': mvaddstr(S_ROW,COL_FOUR,"CORRECT         "); break;
 2058:            case 'y': mvaddstr(S_ROW,COL_FOUR,"HANDIN CORRECT  "); break;
 2059:            case '-': mvaddstr(S_ROW,COL_FOUR,"UNANSWERED      "); break;
 2060:            case 'e': mvaddstr(S_ROW,COL_FOUR,"EXCUSED         "); break;
 2061:            case 'E': mvaddstr(S_ROW,COL_FOUR,"EXCUSED         "); break;
 2062:            case 'n': mvaddstr(S_ROW,COL_FOUR,"HANDIN INCORRECT"); break;
 2063:            case 'N': mvaddstr(S_ROW,COL_FOUR,"INCORRECT       "); break;
 2064:            default : if(entry.answers[num] >= '0' && entry.answers[num] <= '9') {
 2065:                       sprintf(aLine,"HAND-GRADED %c/%c ",entry.answers[num],
 2066: 			      header.weight[num]);
 2067:                       mvaddstr(S_ROW,COL_FOUR,aLine);
 2068:                      }
 2069:                      break;
 2070:          }
 2071:          mvaddstr(S_ROW,COL_FIVE,"OPTION:");
 2072:          
 2073:          mvaddstr(O_ROW,COL_ONE,"M=Main menu");
 2074:          if( second_scr && scr_idx == 1) {
 2075:            mvaddstr(O_ROW,COL_TWO,"N=Next screen");
 2076:            allow_n = 1;
 2077:          }
 2078:          if( second_scr && scr_idx == 2) {
 2079:            mvaddstr(O_ROW,COL_TWO,"P=Prev screen");
 2080:            allow_p = 1;
 2081:          }
 2082:          mvaddstr(O_ROW,COL_THREE,"X=eXit");
 2083:          mvaddstr(O_ROW,COL_FOUR, "RETURN=Enter/Execute");
 2084:          if ( problem->hint && 
 2085: 	      ( 
 2086: 	       (problem->show_hint <= problem->tries) || 
 2087: 	       (entry.answers[num] == 'Y') || 
 2088: 	       (entry.answers[num] == 'y')
 2089: 	       ) 
 2090: 	      )    { 
 2091: 	   allow_hint=1;    mvaddstr(O_ROW,COL_FIVE,"H=Hint"); 
 2092: 	 }
 2093:          mvaddstr(X_ROW,COL_ONE,goto_str);
 2094:          if (problem->next)
 2095:                mvaddstr(X_ROW,COL_FOUR,"RETURN=next problem");
 2096:             else
 2097:                mvaddstr(X_ROW,COL_FOUR,"RETURN=main menu   ");
 2098:          if ( problem->explain ) { allow_explain=1; mvaddstr(X_ROW,COL_FIVE,"E=Explain"); }
 2099:    
 2100:       }
 2101:       get_input(S_ROW,COL_FIVE+7,buf,3);
 2102:       display=0; usr_command=C_DONTCARE;
 2103:       /* DEFAULT ACTIONS on empty input */
 2104:       if(!strlen(buf)) { usr_command = (problem->next? C_FORWARD : C_MENU); } else {
 2105:         switch(toupper(buf[0])) {
 2106:          case 'X': usr_command=C_EXIT;    break;
 2107:          case 'M': usr_command=C_MENU;    break;
 2108: 	 case 'H': usr_command=C_HINT;    break;
 2109:          case 'E': usr_command=C_EXPLAIN; break;
 2110:          case 'N': if( allow_n ) { usr_command=C_NEXTSCR; } break;
 2111:          case 'P': if( allow_p ) { usr_command=C_PREVSCR; } break;
 2112:          default : sscanf(buf,"%d",&whereto);
 2113:                   if(whereto >0 && whereto <= num_questions) usr_command=C_JUMP;
 2114: 		  break;
 2115:         }
 2116:       }
 2117: 
 2118: 
 2119:       /* PROCESS USER COMMAND */
 2120:       switch(usr_command) {
 2121:       case C_FORWARD: /* FORWARDS ONE */
 2122:                 if (problem->next) {
 2123:                    problem=problem->next; display=1; scr_idx = 1; num++;
 2124:                 } else
 2125:                    mvaddstr(X_ROW,COL_FOUR,"RETURN=main menu   ");
 2126:                 break;
 2127:       case C_HINT: /* HINT */
 2128:                 if(allow_hint) {
 2129:                   display_hint(problem->hint);
 2130:                   display=1;
 2131:                   allow_hint = 0;
 2132:                 }
 2133: 		break;
 2134:       case C_EXPLAIN: /* Explain */
 2135:                 if(allow_explain) {
 2136:                   display_hint(problem->explain); display=1;
 2137: 		  allow_explain=0;
 2138: 		}
 2139: 		break;
 2140:       case C_NEXTSCR:  scr_idx = 2; display=1;
 2141:                 break;
 2142:       case C_PREVSCR:  scr_idx = 1; display=1;
 2143:                 break;
 2144:       case C_EXIT: /* EXIT SYSTEM */
 2145:                 ex=1; problem=0; break;
 2146: 
 2147:       case C_MENU: /* RETURN TO MAIN MENU */
 2148:                 problem=0;  break;
 2149: 
 2150:       case C_JUMP: /* JUMP TO SPECIFIC PROBLEM # */
 2151:                    num=whereto-1;
 2152:                    for (problem=first_problem; whereto > 1 && problem->next; whereto--)
 2153:                       problem=problem->next;
 2154:                    display=1;
 2155:                    scr_idx = 1;
 2156:                  break;
 2157:       case C_TIME:     break;
 2158:       case C_DONTCARE: break;
 2159:       }
 2160:    }
 2161: 
 2162:    /* FREE UP MALLOC'ED SPACE - VERY IMPORTANT */
 2163:    capa_mfree(header.weight);
 2164:    capa_mfree(header.partial_credit);
 2165:    capa_mfree(entry.answers);
 2166:    capa_mfree(entry.tries);
 2167:    free_problems(first_problem);
 2168: 
 2169:    if (ex) properly_logout(student_number);
 2170: }
 2171: 
 2172: /* -------------------------------------------------------------------------- */
 2173: /* DISPLAY HELP SCREEN                                                        */
 2174: /* -------------------------------------------------------------------------- */
 2175: void                  /* RETURNS: (nothing)      */
 2176: display_help()        /* ARGUMENTS: (none)       */
 2177: {                     /* LOCAL VARIABLES:        */
 2178:    FILE *fp;          /*    Welcome file pointer */
 2179:    char  buf[255];    /*    Input buffer         */
 2180: 
 2181:    CLEAR();
 2182:    if ((fp=fopen("help.msg","r"))!=NULL) {
 2183:       while (fgets(buf,255,fp))  addstr(buf);
 2184:       fclose(fp);
 2185:    }
 2186:    mypause(22,20);
 2187: }
 2188: 
 2189: 
 2190: /*   A class directory must have   */
 2191: /*     records/                    */
 2192: /*                                 */
 2193: /*  returns: 0  structure is correct, but no set.db files */
 2194: /*          -1  structure is not correct                  */
 2195: /*          >=1 the last set.db                           */
 2196: 
 2197: int
 2198: check_class_get_set(dir_path) char  *dir_path;
 2199: {
 2200:   char   f_name[1024];
 2201:   int    set;
 2202:   
 2203:   if( capa_access(dir_path, F_OK) == 0 ) { /* class dir exists */
 2204:     sprintf(f_name,"%s/records",dir_path);
 2205:     if( capa_access(f_name, F_OK) == 0 ) { /* class/records dir exists */
 2206:       for(set = 1; ; set++ ) {
 2207:         sprintf(f_name,"%s/records/set%d.db",dir_path,set);
 2208:         if(capa_access(f_name, F_OK) == -1 )  break;
 2209:       }
 2210:       set--;
 2211:     } else {
 2212:       set = -1;
 2213:     }
 2214:   } else {
 2215:     set = -1;
 2216:   } 
 2217:   return (set);
 2218: }
 2219: /* -------------------------------------------------------------------------- */
 2220: /* Get Exam and Quiz Path                                                     */
 2221: /*   return  0, 1, 2, 3         */
 2222: /* -------------------------------------------------------------------------- */
 2223: int
 2224: check_exam_quiz_f()
 2225: {
 2226:    char  buf[MAX_BUFFER_SIZE];
 2227:    int   result = 0, configResult=0;
 2228: 
 2229: #ifdef LOGIN_DBUG
 2230:    fprintf(dfp,"CHECK EXAM Access() success,and open(),%s\n",buf); fflush(dfp);
 2231: #endif
 2232:    configResult=read_capa_config("exam_path",buf);
 2233:    if (configResult != 0 && configResult != -1) {
 2234:      Exam_set = check_class_get_set(buf);
 2235:      if(Exam_set > 0 )  {
 2236:        result = 1;
 2237:        sprintf(Exam_path,buf);
 2238:      }
 2239:    }
 2240: #ifdef LOGIN_DBUG
 2241:    fprintf(dfp,"CHECK EXAM = %d,%s\n", result,Exam_path); fflush(dfp);
 2242: #endif
 2243:    configResult=read_capa_config("quiz_path",buf);
 2244:    if (configResult != 0 && configResult != -1) {
 2245:      Quiz_set = check_class_get_set(buf);
 2246:      if(Quiz_set > 0 )  {
 2247:        result = (result | 2);
 2248:        sprintf(Quiz_path,buf);
 2249:      }
 2250:    }
 2251:    
 2252:    return (result);
 2253: }
 2254: 
 2255: /* -------------------------------------------------------------------------- */
 2256: /* DISPLAY MAIN MENU                                                          */
 2257: /* -------------------------------------------------------------------------- */
 2258: void                  /* RETURNS: (nothing) */
 2259: display_menu(student, exam_f, quiz_f) 
 2260: T_student *student;
 2261: int        exam_f, quiz_f;
 2262: {
 2263:    char buff[MAX_BUFFER_SIZE];
 2264:    int  c_y,configResult,term_summary_button=1;
 2265:    
 2266:    configResult=read_capa_config("term_summary_button",buff);
 2267:    if (configResult != 0 && configResult != -1 ) {
 2268:      if (strcasecmp(buff,"no")==0) {
 2269:        term_summary_button=0;
 2270:      }
 2271:    }
 2272: 
 2273:    CLEAR();
 2274: 
 2275:    mvaddstr(1,10,student->s_nm);
 2276:    sprintf(buff,"Section: %d",student->s_sec);
 2277:    mvaddstr(1,50,buff);
 2278: 
 2279:    mvaddstr( 4,25,"  MAIN MENU"); c_y = 6;
 2280:    mvaddstr( c_y,25,"H=Help");    c_y++;
 2281:    if (term_summary_button) { mvaddstr( c_y,25,"S=Summary"); c_y++; }
 2282:    mvaddstr( c_y,25,"T=Try set"); c_y++;
 2283:    mvaddstr( c_y,25,"V=View previous set"); c_y++;
 2284:    if(exam_f) { mvaddstr( c_y,25,"E=view Exam summary"); c_y++; }
 2285:    if(quiz_f) { mvaddstr( c_y,25,"Q=view Quiz summary"); c_y++; }
 2286:    mvaddstr( c_y,25,"X=eXit system");
 2287: 
 2288:    mvaddstr(14,25,"COMMAND:");
 2289: 
 2290:    mvaddstr(17, 5,"Enter a command from the list above and press ENTER/RETURN");
 2291: }
 2292: 
 2293: /* -------------------------------------------------------------------------- */
 2294: /* CONTROL MAIN MENU SELECTIONS                                               */
 2295: /* -------------------------------------------------------------------------- */
 2296: void                                    /* RETURNS: (nothing)     */
 2297: menu_main(student_number,set,section)   /* ARGUMENTS:             */
 2298: char *student_number;                   /*    Student number      */
 2299: int set;                                /*    Set number          */
 2300: int section;                            /*    Section number      */
 2301: {                                       /* LOCAL VARIABLES:       */
 2302:    int       ex=0,                      /*    Exit system flag    */
 2303:              cmd;                       /*    User command        */
 2304:    char      buff[MAX_BUFFER_SIZE];     /*    User command buffer */
 2305:    T_student a_student;
 2306:    int       had_exam, had_quiz, outcome,configResult;
 2307: 
 2308: #ifdef LOGIN_DBUG
 2309:    fprintf(dfp,"MENU in %s sec=%d\n", student_number,section); fflush(dfp);
 2310: #endif
 2311: 
 2312:    outcome = check_exam_quiz_f();
 2313:    had_exam = outcome & 1;
 2314:    had_quiz = outcome & 2;
 2315: 
 2316: #ifdef LOGIN_DBUG
 2317:    fprintf(dfp,"After check %d\n", outcome); fflush(dfp);
 2318: #endif
 2319: 
 2320:    capa_get_student(student_number,&a_student);
 2321:    
 2322:    g_inhibit_response=capa_check_option(OPTION_INHIBIT_RESPONSE,set,section);
 2323:    if (g_inhibit_response < 0 ) g_inhibit_response=0;
 2324: 
 2325:    display_menu(&a_student,had_exam, had_quiz);
 2326:    while (!ex) {
 2327:       do {
 2328:          buff[0] = ' '; buff[1] = 0;
 2329:          get_input(14,34,buff,1);  cmd=toupper(buff[0]);
 2330:       } while (isspace(cmd));
 2331:       move(14,35); clrtoeol();
 2332:       /* PROCESS USER COMMAND */
 2333:       switch(cmd) {
 2334: 
 2335:       case 'H': /* DISPLAY HELP */
 2336:                 display_help();
 2337:                 display_menu(&a_student,had_exam, had_quiz);
 2338:                 break;
 2339:  
 2340:       case 'T': /* TRY CURRENT SET */
 2341:                 try_set(student_number,set,&section);       
 2342:                 display_menu(&a_student,had_exam, had_quiz);
 2343:                 break;
 2344: 
 2345:       case 'V': /* VIEW PREVIOUS SET */
 2346:                 view_previous(student_number,set,&section); 
 2347:                 display_menu(&a_student,had_exam, had_quiz);
 2348:                 break;
 2349: 
 2350:       case 'S': /* DISPLAY TERM SUMMARY */
 2351: 	        configResult=read_capa_config("term_summary_button",buff);
 2352: 		if (configResult != 0 && configResult != -1 ) {
 2353: 		  if ((strcasecmp(buff,"no")==0)) {
 2354: 		    break;
 2355: 		  }
 2356: 		}
 2357: 		term_summary(student_number,set,&section,TERM_SUMMARY);  
 2358: 		display_menu(&a_student,had_exam, had_quiz);
 2359: 		break;
 2360:       case 'E': /* VIEW EXAM SUMMARY */
 2361:                 if( had_exam ) {
 2362:                   chdir(Exam_path);
 2363:                   term_summary(student_number,Exam_set,&section,EXAM_SUMMARY);  
 2364:                   display_menu(&a_student,had_exam, had_quiz);
 2365:                   chdir(Orig_path);
 2366:                 }
 2367:                 break;
 2368:       case 'Q': /* VIEW QUIZ SUMMARY */
 2369:                 if( had_quiz ) {
 2370:                   chdir(Quiz_path);
 2371:                   term_summary(student_number,Quiz_set,&section,QUIZ_SUMMARY);  
 2372:                   display_menu(&a_student,had_exam, had_quiz);
 2373:                   chdir(Orig_path);
 2374:                 }
 2375:                 break;
 2376:       case EOF: /* EXIT SYSTEM */
 2377:       case 'X': ex=1; break;
 2378: 
 2379:       default:  /* INVALID COMMAND */
 2380:                 /* printf("Invalid choice\n"); */
 2381:                 break;
 2382:       }
 2383:    }
 2384: }
 2385: 
 2386: /* -------------------------------------------------------------------------- */
 2387: /* DISPLAY WELCOME MESSAGE WHEN USER LOGS IN                                  */
 2388: /* -------------------------------------------------------------------------- */
 2389: void               /* RETURNS: (nothing)      */
 2390: welcome()          /* ARGUMENTS:         */
 2391: {                  /* LOCAL VARIABLES:        */
 2392:    FILE *fp;       /*    Welcome file pointer */
 2393:    char  buf[TMP_LINE_LENGTH]; /*    Input buffer         */
 2394: 
 2395:    CLEAR();
 2396:    /* sprintf(buf,"This is your %d-time login to this set, good luck!",tries);
 2397:    addstr(buf);
 2398:    */
 2399:    if ((fp=fopen("welcome.msg","r"))!=NULL) {
 2400:       while (fgets(buf,TMP_LINE_LENGTH-1,fp)) addstr(buf);
 2401:       fclose(fp);
 2402:    }
 2403: }
 2404: 
 2405: void print_version()
 2406: {
 2407:   printf("capalogin\n");
 2408:   printf("       CAPA version %s, %s\n",CAPA_VER,COMPILE_DATE);
 2409: }
 2410: 
 2411: /* ------------------------------------------------------------------------- */
 2412: /* DRIVER: INITIALIZE AND GO TO LOGIN                                        */
 2413: /* ------------------------------------------------------------------------- */
 2414: int
 2415: main(int argc, char **argv)
 2416: {                            /* LOCAL VARIABLES:            */
 2417:    char     student_number[MAX_STUDENT_NUMBER+1]; /* Student number         */
 2418:    int      set,             /*    Set number               */
 2419:             section=0,       /*    Section number           */
 2420:             result;          /* stores result from read_capa_config */
 2421:    char     filename[FILE_NAME_LENGTH];   /*    Question filename buffer */
 2422: #if defined(NeXT)
 2423:    char     cwd[FILE_NAME_LENGTH];
 2424: #endif
 2425:    char *class_path, buf[MAX_BUFFER_SIZE],*tty;
 2426:    
 2427:    
 2428:    if (argc > 1) { if (strcmp(argv[1],"-v") == 0) {print_version(); exit(0); } }
 2429: #ifdef LOGIN_DBUG
 2430:    printf("Create login.DBUG file:: argc = %d\n",argc);
 2431:    sprintf(filename,"login.DBUG");
 2432:    if ((dfp=fopen(filename,"a"))==NULL) { printf("Error: can't open login debug\n"); return; }
 2433: #endif /* LOGIN_DBUG */
 2434:    /* GET CURRENT SET NUMBER */
 2435:   for(set = 1; ; set++ ) {
 2436:     sprintf(filename,"set%d.qz",set);
 2437:     if(capa_access(filename, F_OK) == -1 )   break;
 2438:   }
 2439:   set--;
 2440: #if defined(NeXT) 
 2441:    class_path = getwd(cwd);
 2442:    if( class_path ==  NULL ) class_path = cwd;
 2443: #else
 2444:    class_path = getcwd(NULL,512);
 2445:    
 2446: #endif 
 2447:    sprintf(Orig_path,"%s",class_path);
 2448:    free(class_path);
 2449:    /* ---------------------------------------------- CURSES INITIALIZATION */
 2450:    signal(SIGINT , kick_out);
 2451:    signal(SIGALRM, kick_out);
 2452:    signal(SIGFPE, SIG_IGN);
 2453:    initscr(); savetty(); cbreak(); noecho();
 2454:    time(&log_in_time);
 2455:    strncpy(in_t,ctime(&log_in_time),31);
 2456:    in_t[ strlen(in_t)-1 ]=0;    /* Trash newline */
 2457:    tty=ttyname(0);
 2458:    if ( tty == NULL ) {
 2459:      strcpy(in_tty,"UNKNOWN");
 2460:    } else {
 2461:      strcpy(in_tty,tty);
 2462:    }
 2463:    result=read_capa_config("capalogin_goodbye_delay",buf);
 2464:    if (result != 0 && result != -1) {
 2465:      g_delay=atoi(buf);
 2466:    } else {
 2467:      g_delay=5;
 2468:    }
 2469:    result=read_capa_config("capalogin_inactivity_delay",buf);
 2470:    if (result != 0 && result != -1) {
 2471:      g_max_delay=atoi(buf);
 2472:    } else {
 2473:      g_max_delay=60;
 2474:    }
 2475:    welcome();
 2476:    strcpy(student_number, login(&set,&section)); student_number[MAX_STUDENT_NUMBER] = 0;
 2477: #ifdef LOGIN_DBUG
 2478:    fprintf(dfp,"login return:SNum=%s, set=%d, sec=%d\n", student_number,set, section); fflush(dfp);
 2479: #endif
 2480:    menu_main(student_number,set,section);
 2481: #ifdef LOGIN_DBUG
 2482:    fclose(dfp);
 2483: #endif
 2484:    properly_logout(student_number);
 2485:    return 0;
 2486: }
 2487: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>