File:  [LON-CAPA] / capa / capa51 / pProj / capalogin.c
Revision 1.1: download - view: text, annotated - select for diffs
Tue Sep 28 21:26:21 1999 UTC (24 years, 9 months ago) by albertel
Branches: MAIN
CVS tags: HEAD
Initial revision

    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:    T_entry  entry;                       /*    Database entry for a set */
  782:    char     buf[MAX_BUFFER_SIZE], buf2[MAX_BUFFER_SIZE];
  783:    T_header header;                      /*    Problem set header       */
  784:    int      topset=1,                    /*    First displayed set      */
  785:             bottomset,                   /*    Last displayed set       */
  786:             done=0,                      /*    Done flag                */
  787:             line, col;
  788:    int      probs_in_set[MAX_BUFFER_SIZE],/*    # problem set questions  */
  789:             start_at[MAX_BUFFER_SIZE],
  790:             valid_wgt[SMALL_LINE_BUFFER],
  791:             a_valid_wgt,set_start_line,
  792: 	    usr_command,inhibit_response;
  793: 
  794:    /* CALCULATE TERM TOTALS */
  795:   start_at[0] = -2;
  796:   probs_in_set[0]= 0;
  797:   for (set_idx=1; set_idx<=set; set_idx++) {
  798:     if (capa_get_header(&header,set_idx))  return;
  799:     capa_get_entry(&entry,student_number,set_idx);
  800:     sscanf(header.num_questions,"%d", &(probs_in_set[set_idx]) );
  801:     start_at[set_idx] = start_at[set_idx-1]+2*(1+probs_in_set[set_idx-1]/50);
  802:     if ((start_at[set_idx]%12)+2*(1+probs_in_set[set_idx]/50) > 12)
  803:          start_at[set_idx] = 12*(1+start_at[set_idx]/12);
  804:     valid_wgt[set_idx] = 0;
  805:     for (i=0; i<probs_in_set[set_idx]; i++) {
  806:       valid_wgt[set_idx] +=  (header.weight[i] - '0');
  807:       if((entry.answers[i]=='Y') || (entry.answers[i]=='y'))  
  808: 	term_score += (header.weight[i]-'0');
  809:       if((entry.answers[i]=='E') || (entry.answers[i]=='e'))  
  810: 	valid_wgt[set_idx] -= (header.weight[i] - '0');
  811:       if((entry.answers[i]>='0') && (entry.answers[i]<='9'))  
  812: 	term_score += (entry.answers[i] - '0');
  813:     }
  814:     term_total += valid_wgt[set_idx];
  815:     capa_mfree(header.weight);
  816:     capa_mfree(header.partial_credit);
  817:     capa_mfree(entry.answers);
  818:     capa_mfree(entry.tries);
  819:   }
  820: 
  821:    /* FIND TOPSET */
  822:    line = 12*(start_at[set]/12);      /* Top line # of last screen */
  823:    for (topset=set; topset>1 && start_at[topset-1]>=line; topset--);
  824: 
  825:    /* SHOW HEADER */
  826:    CLEAR();
  827:    switch(type) {
  828:      case TERM_SUMMARY:    mvaddstr(1,30,"TERM SUMMARY"); break;
  829:      case EXAM_SUMMARY:    mvaddstr(1,30,"EXAM SUMMARY"); break;
  830:      case QUIZ_SUMMARY:    mvaddstr(1,30,"QUIZ SUMMARY"); break;
  831:    }
  832:    mvaddstr(3,22,"         1         2         3         4         5");
  833:    mvaddstr(4,22,"12345678901234567890123456789012345678901234567890");
  834: 
  835:    /* DISPLAY COMMAND MENU */
  836:    mvaddstr(21,1,"Enter a command from the list below and press ENTER/RETURN    COMMAND:");
  837:    mvaddstr(22,1,"M =Go to main menu  N =Next Page  P =Prev Page");
  838:    /* mvaddstr(22,1,"X =eXit M =Go to main menu  N =Next Page  P =Prev Page"); */
  839:    refresh();
  840: 
  841:    /* SHOW TOTALS */
  842:    /* if capalogin_show_summary_score is set to none don't show it */
  843:    sprintf(buf,"%d sets, total=%3d/%3d (%d%%)", set, term_score, term_total,
  844:       100*term_score/term_total);
  845:    result=read_capa_config("capalogin_show_summary_score",buf2);
  846:    if (result != 0 && result != -1) {
  847:      if (strcasecmp(buf2,"none")==0) {
  848:      } else {
  849:        mvaddstr(19,1,buf);
  850:      }
  851:    } else {
  852:      mvaddstr(19,1,buf);
  853:    }
  854: 
  855:    /* LOOP UNTIL DONE */
  856:   while (!done) {
  857:     /* PRINT 1 LINE SUMMARY PER SET */
  858:     line=5;
  859:     for (set_idx=topset; set_idx<=set; set_idx++) {
  860:       /* don't show summary for set if inhibit response is set*/
  861:       inhibit_response=capa_check_option(OPTION_INHIBIT_RESPONSE,set_idx,*section);
  862:       if (inhibit_response > 0) continue;
  863: 
  864:       set_score=0;
  865:       set_start_line=line;
  866:     /* Stop if not enough lines to summarize set */
  867:       if (line+2*(probs_in_set[set_idx]/50)>16)   break;
  868:       capa_get_header(&header,set_idx);
  869:       capa_get_entry(&entry,student_number,set_idx);
  870:       a_valid_wgt = 0;
  871:        for (i=0, col=0; i<probs_in_set[set_idx]; i++) {
  872:          tmp=0; a_valid_wgt += (header.weight[i] - '0');
  873:          move(line,  22+col); addch(entry.answers[i]);
  874:          move(line+1,22+col); addch(header.weight[i]);
  875:          switch(entry.answers[i]) {
  876:            case 'Y': tmp=header.weight[i] -'0'; break; /* Answer correct */
  877:            case 'y': tmp=header.weight[i] -'0'; break; /* Grading correct */
  878:            case '-': break;        /* Not answered    */
  879:            case 'N': break;        /* Answer incorrect */
  880:            case 'n': break;        /* Grading incorrect */
  881:            case 'e': a_valid_wgt -= (header.weight[i] - '0'); break;  /* Excuse    */
  882:            case 'E': a_valid_wgt -= (header.weight[i] - '0'); break;  /* Excuse    */
  883:            default : if( entry.answers[i] >= '0' && entry.answers[i] <= '9' ) {
  884:                        tmp = entry.answers[i] - '0';
  885:                      }
  886:                      break;
  887:          }
  888:          set_score  += tmp; col++;
  889:          if (!((i+1)%50)) { line += 2; col = 0; }
  890:        }
  891:        capa_mfree(header.weight);
  892:        capa_mfree(header.partial_credit);
  893:        capa_mfree(entry.answers);
  894:        capa_mfree(entry.tries);
  895:        move(line, 22+col);   CLRTOEOL();
  896:        move(line+1, 22+col); CLRTOEOL();
  897:        if(a_valid_wgt == 0) {
  898:          set_score=0;
  899:          sprintf(buf,"%3d:%3d/%3d(%3d%%)  ",set_idx,set_score,a_valid_wgt,set_score);
  900:          mvaddstr(set_start_line,1,buf);
  901:        } else {
  902:          sprintf(buf,"%3d:%3d/%3d(%3d%%)  ",set_idx,set_score,a_valid_wgt,100*set_score/a_valid_wgt);
  903:          mvaddstr(set_start_line,1,buf);
  904:        }
  905:        line += 2;
  906:     }
  907:     bottomset=set_idx-1;
  908: 
  909:       /* Blank out any extra lines */
  910:     if (line < 16) {
  911:      for (set_idx=line; set_idx<=16; set_idx++) {
  912:        move(set_idx,1);
  913:        CLRTOEOL();
  914:      }
  915:     }
  916: 
  917:       /* PROCESS USER COMMAND */
  918:       get_input(21,72,buf,1);
  919:       if(!strlen(buf)) { usr_command = C_FORWARD; } else {
  920:         
  921:           switch(toupper(buf[0])) {
  922:            /* case 'X': usr_command=C_EXIT;    break; */
  923:            case 'M': usr_command=C_MENU;    break;
  924: 	   case 'P': usr_command=C_BACKWARD; break;
  925:            default : usr_command=C_FORWARD;    break;
  926:           }
  927:       }
  928: 
  929:       
  930:       switch(usr_command) {
  931:       case C_DONTCARE: break;
  932:       case C_FORWARD: /* Forwards */
  933:                 if (bottomset<set) { topset=bottomset+1; } else { done=1; }
  934:                 break;
  935:       
  936:       case C_BACKWARD: /* Backwards */
  937:                 if (topset<2) break;
  938:                 line = 12*(start_at[topset-1]/12); /* Top line # of prev screen */
  939:                 for (; topset>1 && start_at[topset-1]>=line; topset--);
  940:                 break;
  941: 
  942:       case C_MENU: /* Menu */
  943:                 done=1;
  944:                 break;
  945:       case C_EXIT: /* Exit */
  946:                 properly_logout(student_number);
  947:                 break;
  948:       default:  /* Invalid command */
  949:                 break;
  950:       }
  951:    }
  952: }
  953: 
  954: void
  955: display_hint(char *h)
  956: {
  957: 
  958:   CLEAR();
  959: 
  960:   wrap(h);
  961:   mypause(22,20);
  962: }
  963: 
  964: #define   A_ROW    20
  965: #define   S_ROW    21
  966: #define   O_ROW    22
  967: #define   X_ROW    23
  968: 
  969: #define   A_COL    14
  970: #define   S_COL    46
  971: #define   H_COL    24
  972: #define   E_COL    39
  973: #define   X_COL    8
  974: #define   R_COL    57
  975: #define   U_ANS_CHAR  32
  976: 
  977: /* =============================================================================
  978: 0001234567890123456789012345678901234567890123456789012345678901234567890123456789
  979: A
  980: S1OPTION/ANSWER 12345678901234 -----            *Unanswered
  981: O2Options :M = Main Menu  :7 = go to #7  :N = Next screen  RETURN = Enter/Execute
  982: X3        :X = eXit       :H = Show Hint :E = Explain      RETURN = Next Problem
  983:   0123456789012345678901234567890123456789012345678901234567890
  984:           ^     ^         ^              ^      ^          ^
  985:           X     A         H              E      S          R
  986: */
  987: int  show_prior_response(Problem_t *p,int hgr,int prev_ans,int tried,int *allow_h)
  988: {
  989:   char     *c_answer_str, tmp_str[MAX_BUFFER_SIZE];
  990:   char     *response="Incorrect",*answered="Answered";
  991:   int       can_answer;
  992:   
  993:   if( hgr == '0' || p->ans_type==ANSWER_IS_SUBJECTIVE) {
  994:     switch(prev_ans) {
  995:       case 'Y': can_answer=NAY; *allow_h=1;
  996:                 c_answer_str = answers_string(ANSWER_STRING_MODE,p);
  997:                 move(A_ROW,A_COL); clrtoeol();  
  998:                 mvaddstr(A_ROW,A_COL,c_answer_str); capa_mfree(c_answer_str);
  999:                 move(S_ROW,S_COL); clrtoeol();
 1000:                 mvaddstr(S_ROW,S_COL,"**Correct              "); break;
 1001:       case 'y': can_answer=NAY; *allow_h=1;
 1002:                 c_answer_str = answers_string(ANSWER_STRING_MODE,p);
 1003:                 move(A_ROW,A_COL); clrtoeol();
 1004:                 mvaddstr(A_ROW,A_COL,c_answer_str); capa_mfree(c_answer_str);
 1005:                 move(S_ROW,S_COL); clrtoeol();
 1006:                 mvaddstr(S_ROW,S_COL,"*Hand-graded Correct      "); break;
 1007:       case '-': can_answer=YAK; move(S_ROW,S_COL); clrtoeol();
 1008:                 mvaddstr(S_ROW,S_COL,"*Unanswered               "); break;
 1009:       case 'E': can_answer=NAY; move(S_ROW,S_COL); clrtoeol();
 1010:                 mvaddstr(S_ROW,S_COL,"*Excused                  "); break;
 1011:       case 'e': can_answer=NAY; move(S_ROW,S_COL); clrtoeol();
 1012:                 mvaddstr(S_ROW,S_COL,"*Excused                  "); break;
 1013:       case 'n': can_answer=NAY; move(S_ROW,S_COL); clrtoeol();
 1014:                 mvaddstr(S_ROW,S_COL,"*Hand-graded Incorrect    "); break;
 1015:     case '0': case '1': case '2': case '3': case '4': case '5': 
 1016:     case '6': case '7': case '8': case '9':
 1017:       response=answered;
 1018:     case 'N':   if ( tried < p->tries ) {
 1019:                   can_answer=YAK;
 1020: 		  if( (p->tries - tried) == 1 ) {
 1021: 		    sprintf(tmp_str,"*%s, ONE try left!!",response);
 1022: 		  } else {
 1023: 		    sprintf(tmp_str,"*%s, tries %2d/%2d   ",response,tried,p->tries);
 1024: 		  }
 1025:                 } else {
 1026: 		  can_answer=NAY;
 1027: 		  sprintf(tmp_str,  "*%s, no more tries",response);
 1028: 		}
 1029:                 move(S_ROW,S_COL); clrtoeol();
 1030:                 mvaddstr(S_ROW,S_COL,tmp_str); 
 1031:                 if( (can_answer == YAK) && (p->ans_op == ANS_AND) && (p->ans_cnt > 1)) {
 1032:                    sprintf(tmp_str, " Entering answer   1 of %3d     ",p->ans_cnt);
 1033:                    mvaddstr(A_ROW,S_COL,tmp_str);
 1034:                 }
 1035:                 break;
 1036:     }
 1037:   } else {  /* hand graded question */
 1038:     can_answer=NAY;
 1039:     move(S_ROW,S_COL); clrtoeol();
 1040:     mvaddstr(S_ROW,S_COL,"*Hand-graded question     ");
 1041:   }
 1042:   /* ------------------------------------------------------------------ */
 1043:   if (*allow_h && 
 1044:       p->hint && 
 1045:       (
 1046:        ( p->show_hint <= tried ) || 
 1047:        ( prev_ans == 'y' ) ||
 1048:        ( prev_ans == 'Y' )
 1049:        )
 1050:       ) {
 1051:     mvaddstr(X_ROW,H_COL,":H = Show Hint");
 1052:   } else {
 1053:     *allow_h = 0;
 1054:   }
 1055:   if (p->next)
 1056:     mvaddstr(X_ROW,R_COL,"RETURN = Next Problem");
 1057:   else
 1058:     mvaddstr(X_ROW,R_COL,"RETURN = Main Menu   ");
 1059:   
 1060:   return (can_answer);
 1061:   
 1062: }
 1063: int  show_prior_inhibited_response(Problem_t *p,int hgr,int prev_ans,int tried,
 1064: 				   int *allow_h)
 1065: {
 1066:   char     tmp_str[MAX_BUFFER_SIZE];
 1067:   int      can_answer;
 1068:   
 1069:   if( hgr == '0' ) {
 1070:     switch(prev_ans) {
 1071:       case '-': can_answer=YAK; move(S_ROW,S_COL); clrtoeol();
 1072:                 mvaddstr(S_ROW,S_COL,"*Unanswered               "); break;
 1073:       case 'E':
 1074:       case 'e':
 1075:       case 'n':
 1076:       case 'y': 
 1077:       case 'Y': 
 1078:       case 'N': if ( tried < p->tries ) {
 1079: 	          can_answer=YAK;
 1080: 		  if( (p->tries - tried) == 1 ) {
 1081: 		    sprintf(tmp_str,"*Answered, ONE try left!! ");
 1082: 		  } else {
 1083: 		    sprintf(tmp_str,"*Answered, tries %2d/%2d    ",tried,p->tries);
 1084: 		  }
 1085:                 } else {
 1086: 		  can_answer=NAY;
 1087: 		  sprintf(tmp_str,  "*Answered, no more tries ");
 1088: 		}
 1089:                 move(S_ROW,S_COL); clrtoeol();
 1090:                 mvaddstr(S_ROW,S_COL,tmp_str); break;
 1091:            
 1092:     }
 1093:   } else {  /* hand graded question */
 1094:     can_answer=NAY;
 1095:     move(S_ROW,S_COL); clrtoeol();
 1096:     mvaddstr(S_ROW,S_COL,"*Hand-graded question     ");
 1097:   }
 1098:   /* ------------------------------------------------------------------ */
 1099:   if (*allow_h && p->hint && ( p->show_hint <= tried)){
 1100:     mvaddstr(X_ROW,H_COL,":H = Show Hint");
 1101:   } else {
 1102:     *allow_h = 0;
 1103:   }
 1104:   if (p->next)
 1105:     mvaddstr(X_ROW,R_COL,"RETURN = Next Problem");
 1106:   else
 1107:     mvaddstr(X_ROW,R_COL,"RETURN = Main Menu   ");
 1108:   
 1109:   return (can_answer);
 1110:   
 1111: }
 1112: /* -------------------------------------------- dbug --------------------- */
 1113: void
 1114: print_unit_components(FILE *fp,Unit_t *t) 
 1115: {
 1116:   Unit_E  *ue_p;
 1117: 
 1118:   fprintf(fp,"  Unit::[%s] = %g * ", t->u_symbol, t->u_scale);
 1119:   for(ue_p=t->u_list; ue_p ; ue_p = ue_p->ue_nextp) {
 1120:     fprintf(fp,"(%g*%s^%g) ",ue_p->ue_scale,ue_p->ue_symbol,ue_p->ue_exp);
 1121:   }
 1122:   fprintf(fp,"\n"); fflush(fp);
 1123: 
 1124: }
 1125: 
 1126: 
 1127: #define    ANSWER_STRING_LENG       64
 1128: #define    UNIT_STRING_LENG         64
 1129: #define    FORMAT_STRING_LENG       32
 1130: 
 1131: /* ------------------------------------------------------------------- */
 1132: int  give_response(Problem_t *p,char **a,int cnt,int *tried,int *log_char)
 1133: {
 1134:   int      can_answer;
 1135:   char     tmp_str[MAX_BUFFER_SIZE], *c_answer_str;
 1136: 
 1137: 
 1138:   switch( capa_check_answers(p,a,cnt) ) {
 1139: 
 1140:     case  EXACT_ANS:  move(A_ROW,S_COL); clrtoeol();
 1141:                       mvaddstr(A_ROW,S_COL,"*Yes Computer gets:"); 
 1142:                       c_answer_str = answers_string(ANSWER_STRING_MODE, p);
 1143:                       move(S_ROW,S_COL); clrtoeol();
 1144:                       mvaddstr(S_ROW,S_COL,c_answer_str);
 1145:                       capa_mfree((char *)c_answer_str);
 1146:                      *log_char='Y'; can_answer=NAY;
 1147:                       if( *tried < TRY_BOUND)  (*tried)++;
 1148:                       break;
 1149:     case  APPROX_ANS: 
 1150:                       move(A_ROW,S_COL); clrtoeol();
 1151:                       mvaddstr(A_ROW,S_COL,"*Yes Computer gets:");
 1152:                       c_answer_str = answers_string(ANSWER_STRING_MODE, p);
 1153:                       if(cnt == 1 ) {
 1154:                         move(S_ROW,S_COL); clrtoeol();
 1155:                         mvaddstr(S_ROW,S_COL,c_answer_str);
 1156:                       } else {  /* more than one answer to check ANS_AND */
 1157:                         move(S_ROW,S_COL); clrtoeol();
 1158:                         mvaddstr(S_ROW,S_COL,"*Yes Correct Answers See Above");
 1159:                         move(A_ROW,A_COL); clrtoeol();
 1160:                         mvaddstr(A_ROW,A_COL,c_answer_str);
 1161:                       }
 1162:                       capa_mfree((char *)c_answer_str);
 1163:                      *log_char='Y'; can_answer=NAY;
 1164:                       if(*tried < TRY_BOUND)  (*tried)++;
 1165:                       break;
 1166:     case  SIG_FAIL:   move(S_ROW,S_COL); clrtoeol();  
 1167:                       mvaddstr(S_ROW,S_COL,"*Adjust Sig. Figs. ");
 1168:                      *log_char='S'; can_answer=YAK;
 1169:                       break;
 1170:     case  UNIT_FAIL:  move(S_ROW,S_COL); clrtoeol();  
 1171:                       mvaddstr(S_ROW,S_COL,"*Units incorrect   ");
 1172:                      *log_char='U'; can_answer=YAK;
 1173:                       break;
 1174:     case  UNIT_NOTNEEDED:  move(S_ROW,S_COL); clrtoeol();  
 1175:                       mvaddstr(S_ROW,S_COL,"*Only a number required");
 1176:                      *log_char='U'; can_answer=YAK;
 1177:                       break;
 1178:     case  NO_UNIT:    move(S_ROW,S_COL); clrtoeol();  
 1179:                       mvaddstr(S_ROW,S_COL,"*Units required    ");
 1180:                      *log_char='u'; can_answer=YAK;
 1181:                       break;
 1182:     case  BAD_FORMULA:move(S_ROW,S_COL); clrtoeol();  
 1183:                       mvaddstr(S_ROW,S_COL,"*Unable to interpret formula");
 1184:                      *log_char='F'; can_answer=YAK;
 1185:                       break;
 1186:     case  ANS_CNT_NOT_MATCH:
 1187:                       move(S_ROW,S_COL); clrtoeol();  
 1188:                       mvaddstr(S_ROW,S_COL,"*Invalid number of answers");
 1189:                      *log_char='C'; can_answer=YAK;
 1190:                       break;
 1191:     case  INCORRECT: 
 1192:                       if(*tried < TRY_BOUND)  (*tried)++;
 1193: 		      if ( *tried < p->tries ) {
 1194: 			can_answer=YAK;
 1195: 			if( (p->tries - *tried) == 1 ) {
 1196: 			  sprintf(tmp_str,"*Incorrect, ONE try left!!");
 1197: 			} else {
 1198: 			  sprintf(tmp_str,"*Incorrect, tries %2d/%2d   ",*tried,p->tries);
 1199: 			}
 1200: 		      } else {
 1201: 			can_answer=NAY;
 1202: 			sprintf(tmp_str,  "*Incorrect, no more tries");
 1203: 		      }
 1204:                       move(S_ROW,S_COL); clrtoeol(); 
 1205:                       mvaddstr(S_ROW,S_COL, tmp_str);
 1206:                       if( (can_answer == YAK) && (p->ans_op == ANS_AND) && (p->ans_cnt > 1)  ) {
 1207:                          sprintf(tmp_str, " Entering answer   1 of %3d     ",p->ans_cnt);
 1208:                          mvaddstr(A_ROW,S_COL,tmp_str);
 1209:                       }
 1210: 	             *log_char='N';
 1211: 	              break;
 1212:   }
 1213:    
 1214:   return (can_answer);
 1215: }
 1216: 
 1217: int  give_inhibited_response(Problem_t *p,char **a,int cnt,int *tried,int *log_char)
 1218: {
 1219:   int      can_answer;
 1220:   char     tmp_str[MAX_BUFFER_SIZE];
 1221: 
 1222: 
 1223:   switch( capa_check_answers(p,a,cnt) ) {
 1224: 
 1225: 
 1226:     case  EXACT_ANS:  *log_char='Y'; break;
 1227:     case  APPROX_ANS: *log_char='Y'; break;
 1228:     case  SIG_FAIL:   *log_char='S'; break;
 1229:     case  UNIT_FAIL:  *log_char='U'; break;
 1230:     case  UNIT_NOTNEEDED: *log_char='U'; break;
 1231:     case  NO_UNIT:    *log_char='u'; break;
 1232:     case  BAD_FORMULA:*log_char='F'; break;
 1233:     case  INCORRECT:  *log_char='N'; break;
 1234:     case ANS_CNT_NOT_MATCH: *log_char='C'; break;
 1235:   }
 1236:   
 1237:   if(*tried < TRY_BOUND)  (*tried)++;
 1238:   if ( *tried < p->tries ) {
 1239:     can_answer=YAK;
 1240:     if( (p->tries - *tried) == 1 ) {
 1241:       sprintf(tmp_str,"*Answered, ONE try left!! ");
 1242:     } else {
 1243:       sprintf(tmp_str,"*Answered, tries %2d/%2d    ",*tried,p->tries);
 1244:     }
 1245:   } else {
 1246:     can_answer=NAY;
 1247:     sprintf(tmp_str,  "*Answered, no more tries ");
 1248:   }
 1249:   move(S_ROW,S_COL); clrtoeol(); 
 1250:   mvaddstr(S_ROW,S_COL, tmp_str);
 1251:   return (can_answer);
 1252: }
 1253: 
 1254: int  ask_what_prob(int q_cnt, char *ans)
 1255: {
 1256:   int  not_ok=1,num,anslength,i,j;
 1257:   char buf[5],buf2[MAX_BUFFER_SIZE];
 1258:   
 1259:   move(14,35); clrtoeol();
 1260:   move(17,5);  clrtoeol();
 1261:   do {
 1262:      move(14,35); clrtoeol();
 1263:      move(15,0);  clrtoeol();
 1264:      mvaddstr(15,13,"What problem number:");
 1265:      move(17,0);  clrtoeol();
 1266:      mvaddstr(17,16,"         1         2         3         4         5");
 1267:      mvaddstr(18,16,"12345678901234567890123456789012345678901234567890");
 1268:      anslength=strlen(ans);
 1269:      for(i=0;i<=(anslength/50);i++) {
 1270:        if ( g_inhibit_response ) {
 1271: 	 for(j=50*i;(j<((i+1)*50))&&(j<anslength);j++) {
 1272: 	   if (ans[j]=='-') 
 1273: 	     buf2[j-(50*i)]='-';
 1274: 	   else
 1275: 	     buf2[j-(50*i)]='A';
 1276: 	 }
 1277: 	 buf2[j-(50*i)]='\0';
 1278:        } else {
 1279: 	 strncpy(buf2,&(ans[50*i]),50);
 1280:        }
 1281:        buf2[50]='\0';
 1282:        mvaddstr(19+i,16,buf2);
 1283:        if (anslength > 50 ) {
 1284: 	 sprintf(buf2,"%3d-%3d",i*50+1,(i+1)*50);
 1285: 	 mvaddstr(19+i,5,buf2);
 1286:        }
 1287:      }
 1288:      do { get_input(15,34,buf,4); } while(!strlen(buf));
 1289:      sscanf(buf,"%d",&num);
 1290:      if (num<1 || num>q_cnt) {
 1291:         move(21,5); clrtoeol();
 1292:         mvaddstr(21,15,"  Error: Invalid problem number\n");
 1293:      } else {
 1294:         not_ok = 0;
 1295:      }
 1296:   } while (not_ok);
 1297: 
 1298:   return (num);
 1299: }
 1300: 
 1301: /* gather subjective answers from student */
 1302: 
 1303: #define    BS    8
 1304: #define    DEL   127
 1305: #define    ESC   27
 1306: 
 1307: #define    COLON 58
 1308: 
 1309: #define EDIT_HEIGHT 21
 1310: #define EDIT_WIDTH 80
 1311: #define MENULINE EDIT_HEIGHT
 1312: 
 1313: void refresh_editor (char **sbuf_pp,int cx,int cy) {
 1314:   int i;
 1315:   CLEAR();
 1316:   echo();
 1317:   mvaddstr(MENULINE,0,"Type in the answer, use up, down, left, right keys to move curser");
 1318:   mvaddstr(MENULINE+1,0,"Enter ctrl-e to exit and submit answer");
 1319:   mvaddstr(MENULINE+2,0,"Enter ctrl-f to forget answer");
 1320:   for(i=0;i<EDIT_HEIGHT;i++) { mvaddstr(i,0,sbuf_pp[i]); }
 1321:   move(cy,cx); refresh(); noecho();
 1322: }
 1323: 
 1324: void init_editor(char*** sbuf_pp)
 1325: {
 1326:   int   ww=EDIT_WIDTH, hh=EDIT_HEIGHT,i;
 1327:   *sbuf_pp = (char **)capa_malloc(sizeof(char *),hh);
 1328:   for(i=0;i<hh;i++) {
 1329:     (*sbuf_pp)[i] = (char *)capa_malloc(sizeof(char)*ww+1,1);
 1330:   }
 1331:   CLEAR();echo();
 1332:   mvaddstr(MENULINE,0,"Type in the answer, use up, down, left, right keys to move cursor");
 1333:   mvaddstr(MENULINE+1,0,"Enter ctrl-e to exit and submit answer");
 1334:   mvaddstr(MENULINE+2,0,"Enter ctrl-f to forget answer");
 1335:   move(0,0); refresh(); noecho();
 1336: }
 1337: 
 1338: void remove_character(char** sbuf_pp,int *cx,int *cy)
 1339: {
 1340:   int sx=(*cx)-1,sy=*cy;
 1341:   char temp,*temp_p;
 1342:   if (*cx==0) { 
 1343:     int abovelen,curlen,diff,i,j;
 1344:     if (*cy==0) { beep();return;}
 1345:     abovelen=strlen(sbuf_pp[(*cy-1)]);
 1346:     curlen=strlen(sbuf_pp[*cy]);
 1347:     if (abovelen > 0) sbuf_pp[(*cy)-1][abovelen-1]='\0';
 1348:     if ((abovelen+curlen) < EDIT_WIDTH) {
 1349:       strcat(sbuf_pp[(*cy)-1],sbuf_pp[*cy]);
 1350:       memset(sbuf_pp[(*cy)],'\0',EDIT_WIDTH+1);
 1351:       temp_p=sbuf_pp[*cy];
 1352:       i=*cy;
 1353:       while(i<EDIT_HEIGHT-1) {
 1354: 	sbuf_pp[i]=sbuf_pp[i+1];
 1355: 	echo();move(i,0);CLRTOEOL();mvaddstr(i,0,sbuf_pp[i]);noecho();
 1356: 	i++;
 1357:       }
 1358:       sbuf_pp[EDIT_HEIGHT-1]=temp_p;
 1359:       echo();move(EDIT_HEIGHT-1,0);CLRTOEOL();noecho();
 1360:     } else {
 1361:       diff=EDIT_WIDTH-abovelen;
 1362:       strncat(sbuf_pp[(*cy)-1],sbuf_pp[*cy],diff);
 1363:       i=diff;j=0;
 1364:       while(sbuf_pp[*cy][i]!='\0') {
 1365: 	sbuf_pp[*cy][j]=sbuf_pp[*cy][i];
 1366: 	i++;j++;
 1367:       }
 1368:       memset(&(sbuf_pp[(*cy)][j]),'\0',EDIT_WIDTH+1-j);
 1369:     }
 1370:     echo();move(*cy,0); CLRTOEOL(); mvaddstr(*cy,0,sbuf_pp[*cy]);noecho();
 1371:     (*cy)--;
 1372:     echo();move(*cy,0); CLRTOEOL(); mvaddstr(*cy,0,sbuf_pp[*cy]);noecho();
 1373:     if ( EDIT_WIDTH == ((*cx)=(abovelen-1))) (*cx)--;
 1374:     if (abovelen==0) *cx=0;
 1375:     echo();move(*cy,*cx);noecho();
 1376:   } else {
 1377:     echo();move(sy,sx);noecho();
 1378:     temp=sbuf_pp[sy][sx]=sbuf_pp[sy][sx+1];
 1379:     sx++;
 1380:     while(temp!='\0') {
 1381:       echo(); ADDCH(temp); noecho();
 1382:       temp=sbuf_pp[sy][sx]=sbuf_pp[sy][sx+1];
 1383:       sx++;
 1384:     }
 1385:     echo(); ADDCH(' '); noecho();
 1386:     (*cx)--;
 1387:   }
 1388:   echo();move(*cy,*cx);noecho();
 1389: }
 1390: 
 1391: void break_line      (char** sbuf_pp,int *cx,int *cy)
 1392: {
 1393:   int sx=*cx,sy=*cy,i;
 1394:   if (sy < EDIT_HEIGHT-1) {
 1395:     capa_mfree(sbuf_pp[EDIT_HEIGHT-1]);
 1396:     i=EDIT_HEIGHT-1;
 1397:     while (i-1 > sy) {
 1398:       sbuf_pp[i]=sbuf_pp[i-1];
 1399:       move(i,0);CLRTOEOL();mvaddstr(i,0,sbuf_pp[i]);
 1400:       i--;
 1401:     }
 1402:     sbuf_pp[sy+1]=capa_malloc(sizeof(char)*EDIT_WIDTH+1,1);
 1403:   }
 1404:   strcat(sbuf_pp[sy+1],&(sbuf_pp[sy][sx]));
 1405:   memset(&(sbuf_pp[sy][sx]),'\0',EDIT_WIDTH+1-sx);
 1406:   *cx=0;
 1407:   (*cy)++;
 1408:   move(sy,0);CLRTOEOL();mvaddstr(sy,0,sbuf_pp[sy]);
 1409:   move(sy+1,0);CLRTOEOL();mvaddstr(sy+1,0,sbuf_pp[sy+1]);
 1410: }
 1411: 
 1412: /* FIXME catch funtion keys and others? */
 1413: void handle_esc      (unsigned char ca,unsigned char cb,char** sbuf_pp,int *cx,int *cy)
 1414: {
 1415:   if( ca!='[') return;
 1416:   switch (cb) {
 1417:   case 'A':/* KEY_UP */
 1418:     if(*cy>0){
 1419:       (*cy)--;
 1420:       while(*cx>0 && sbuf_pp[*cy][(*cx)-1]=='\0') (*cx)--; /* goto end of line */
 1421:     } else {
 1422:       beep();
 1423:     }
 1424:     break;
 1425:   case 'B': /* KEY_DOWN */
 1426:     if (*cy<(EDIT_HEIGHT-1)) {
 1427:       (*cy)++;
 1428:       while(*cx>0 && sbuf_pp[*cy][(*cx)-1]=='\0') (*cx)--; /* goto end of line */
 1429:     } else {
 1430:       beep();
 1431:     }
 1432:     break;
 1433:   case 'C': /* KEY_RIGHT */
 1434:     if ( *cx<(EDIT_WIDTH-1) && sbuf_pp[*cy][(*cx)]!='\0' ) { 
 1435:       (*cx)++; 
 1436:     } else {
 1437:       if (*cy<(EDIT_HEIGHT-1)) {
 1438: 	(*cy)++; *cx=0; 
 1439:       } else {
 1440: 	beep();
 1441:       }
 1442:     }
 1443:     break;
 1444:   case 'D': /* KEY_LEFT */
 1445:     if(*cx>0) {
 1446:       (*cx)--;
 1447:     } else {
 1448:       if(*cy>0) { 
 1449: 	(*cy)--;
 1450: 	*cx=strlen(sbuf_pp[*cy]);
 1451: 	if (*cx==EDIT_WIDTH) (*cx)--;
 1452:       } else { 
 1453: 	beep(); 
 1454:       }
 1455:     }
 1456:     break;
 1457:   default: beep(); return; break;
 1458:   }
 1459:   echo(); move(*cy,*cx); refresh(); noecho();
 1460: }
 1461: 
 1462: void handle_error    (unsigned char c,char** sbuf_pp,int cx,int cy) 
 1463: {
 1464:   beep();
 1465: }
 1466: 
 1467: /*FIXME Slower than whale shit*/
 1468: void insert_character(unsigned char c,char** sbuf_pp,int *cx,int *cy) 
 1469: {
 1470:   int sx=*cx,sy=*cy;
 1471:   unsigned char temp;
 1472:   while(c!='\0') {
 1473:     if (sx == EDIT_WIDTH) {
 1474:       sx=0;sy++;
 1475:       if (sy == EDIT_HEIGHT) {
 1476: 	sy--;sx=EDIT_WIDTH;c='\0';break;
 1477:       }
 1478:     }	
 1479:     echo(); ADDCH(c); noecho();
 1480:     temp=sbuf_pp[sy][sx];
 1481:     sbuf_pp[sy][sx]=c;
 1482:     c=temp;
 1483:     sx++;
 1484:   }
 1485:   sbuf_pp[sy][sx]=c;
 1486:   (*cx)++;
 1487:   if (*cx == EDIT_WIDTH) {
 1488:       *cx=0;(*cy)++;
 1489:       if (*cy == EDIT_HEIGHT) {
 1490: 	(*cy)--;*cx=EDIT_WIDTH-1;
 1491:       }
 1492:   }
 1493:   move(*cy,*cx);refresh();
 1494: }
 1495: 
 1496: int handle_keystrokes_editor(char** sbuf_pp)
 1497: {
 1498:   int   done = 0, forget = 0, cx=0,cy=0;
 1499:   unsigned char c,ca,cb;
 1500: 
 1501:   while (!done) {
 1502:     move(cy,cx);refresh();
 1503:     c=getch();
 1504:     switch(c) {
 1505:     case BS: case DEL:
 1506:       remove_character(sbuf_pp,&cx,&cy);
 1507:       break;
 1508:     case CR: case LF:
 1509:       break_line(sbuf_pp,&cx,&cy);
 1510:       break;
 1511:     case ESC:
 1512:       ca=getch();cb=getch();
 1513:       handle_esc(ca,cb,sbuf_pp,&cx,&cy);
 1514:       break;
 1515:     case 5: /*ctrl-e*/
 1516:       done=1;
 1517:       break;
 1518:     case 6: /*ctrl-f*/
 1519:       done=1;
 1520:       forget=1;
 1521:       break;
 1522:     case 12:
 1523:       refresh_editor(sbuf_pp,cx,cy);
 1524:       break;
 1525:     default:
 1526:       if (c < 32 || c>126) {
 1527: 	handle_error(c,sbuf_pp,cx,cy);
 1528:       } else {
 1529: 	insert_character(c,sbuf_pp,&cx,&cy);
 1530:       }
 1531:       break;
 1532:     }
 1533:   }
 1534:   return forget;
 1535: }
 1536: 
 1537: int editor(char*** sbuf_pp)
 1538: {
 1539:   init_editor(sbuf_pp);
 1540:   return handle_keystrokes_editor(*sbuf_pp);
 1541: }
 1542: 
 1543: 
 1544: int
 1545: answer_subjective(student_number,set,section,prob)
 1546: char  *student_number; 
 1547: int    set; 
 1548: int   *section;
 1549: int    prob;
 1550: {
 1551:   int i,length;
 1552:   char date_str[DATE_LENGTH];
 1553:   char **sbuf_pp,answer[(EDIT_HEIGHT*(EDIT_WIDTH+1))+1];
 1554:   char submissions_str[(EDIT_HEIGHT*(EDIT_WIDTH+1))+MAX_BUFFER_SIZE];
 1555:   time_t     curtime;
 1556: 
 1557:   time(&curtime);
 1558:   if( capa_check_date(CHECK_DUE_DATE,student_number,*section,set) > 0 ) {
 1559:     capa_get_date(CHECK_DUE_DATE,student_number,*section,set,date_str);
 1560:     sprintf(answer,"Sorry, the due date was: %s",date_str);
 1561:     move(20,1); clrtobot(); addstr(answer); mypause(23,1);
 1562:     return 0;
 1563:   }
 1564: 
 1565:   if (editor(&sbuf_pp)) { return 0; }
 1566: 
 1567:   answer[0]='\0';
 1568:   for(i=0;i<EDIT_HEIGHT;i++) {
 1569:     if (strlen(sbuf_pp[i]) > 0) {
 1570:       strcat(answer,sbuf_pp[i]);
 1571:       length=strlen(answer);
 1572:       answer[length]='\n';
 1573:       answer[length+1]='\0';
 1574:     }
 1575:     capa_mfree((char *)sbuf_pp[i]);
 1576:   }
 1577:   capa_set_subjective(set,prob,student_number,answer);
 1578:   sprintf(submissions_str,"%d\t%s\t",prob,answer);
 1579:   log_submissions(student_number,set,submissions_str);
 1580:   capa_mfree((char *)sbuf_pp);
 1581:   return 1;
 1582: }
 1583: 
 1584: void set_entry_tries(int *tried, char *tries, int num, int num_questions) {
 1585:   if((tried[num] >=0) && (tried[num] <= TRY_BOUND) ) {
 1586:     if(tried[num] < 10 ) {
 1587:       tries[3*num]   = ' ';
 1588:       tries[3*num+1] = tried[num] + '0';
 1589:       if(num < num_questions-1)  tries[3*num+2] = ',';
 1590:     } else {
 1591:       tries[3*num]   = (int)(tried[num]/10) + '0';
 1592:       tries[3*num+1] = (tried[num] % 10) + '0';
 1593:       if(num < num_questions-1)  tries[3*num+2] = ',';
 1594:     }
 1595:   } else {
 1596:     tries[3*num]   = ' ';
 1597:     tries[3*num+1] = 1 + '0';
 1598:     if(num < num_questions-1)  tries[3*num+2] = ',';
 1599:   }
 1600: }
 1601: 
 1602: /* -------------------------------------------------------------------------- */
 1603: /* LET THE USER ANSWER THE CURRENT PROBLEM SET QUESTIONS                      */
 1604: /* -------------------------------------------------------------------------- */
 1605: void                                
 1606: try_set(student_number,set,section) 
 1607: char  *student_number; 
 1608: int    set; 
 1609: int   *section;
 1610: {
 1611:    char       a_student_number[MAX_STUDENT_NUMBER+1];
 1612:    time_t     curtime;
 1613:    T_header   header;
 1614:    Problem_t *first_problem, *p;
 1615:    T_entry    entry;
 1616:    char       answer[256], *a_str, **ans_strs;
 1617:    int        num, offset, num_questions, start_from, leng;
 1618:    char      *log_string,submissions_str[MAX_BUFFER_SIZE];
 1619:    int       *tried,answered;
 1620:    int        scr_idx=1, display=1, second_scr, canAnswer;
 1621:    int        usr_command, whereto, allow_hint=0, ex=0;
 1622:    char       u_input[64], date_str[DATE_LENGTH], one_line[81];
 1623:    int        log_char, i, j, allow_n, allow_p, allow_subj;
 1624:    
 1625:    strncpy(a_student_number,student_number,MAX_STUDENT_NUMBER+1);
 1626:    time(&curtime); /* Is due date past? */
 1627:    /* ---------------------------------------- check due date */
 1628: #ifndef NO_DATE_CHECK
 1629:    /* ===> if ( compare_datetime(curtime,header.due_date) > 0) { */
 1630:    if( capa_check_date(CHECK_DUE_DATE,student_number,*section,set) > 0 ) {
 1631:       capa_get_date(CHECK_DUE_DATE,student_number,*section,set,date_str);
 1632:       sprintf(answer,"  Sorry, the due date was: %s",date_str); 
 1633:       move(17,1); clrtoeol(); mvaddstr(17,15,answer);   mypause(19,17);
 1634:       return;
 1635:    }
 1636: #ifdef LOGIN_DBUG
 1637:   fprintf(dfp,"Tryset():(sec=%d,set=%d)[%s]\n",*section,set,date_str); fflush(dfp);
 1638: #endif /* LOGIN_DBUG */
 1639: #endif /* NO_DATE_CHECK */
 1640: 
 1641:    offset=capa_get_entry(&entry,student_number,set);
 1642:    capa_get_header(&header,set);
 1643:    if (offset<0) offset = -offset;  /* newly created entry */
 1644:    
 1645: #ifdef LOGIN_DBUG
 1646:    fprintf(dfp,"P set=%d,SN=%s,ANS=%s,TRY=%s\n",set,a_student_number,entry.answers,entry.tries); fflush(dfp);
 1647: #endif
 1648:    num = capa_parse(set,&first_problem,a_student_number,&num_questions,NULL);
 1649:    
 1650: #ifdef LOGIN_DBUG
 1651:   fprintf(dfp,"ParseSource:=%d\n",num); fflush(dfp);
 1652: #endif /* LOGIN_DBUG */
 1653: 
 1654:    /* DEBUGGING: make sure num_questions is plausible */
 1655:    if (num_questions>1000 || num_questions<=0)   properly_logout(student_number);
 1656:    
 1657:    start_from=ask_what_prob(num_questions,entry.answers);
 1658:    
 1659:    /* initialize log string to all '-' */
 1660:    tried = (int *)capa_malloc(num_questions+1,sizeof(int));
 1661:    log_string = (char *)capa_malloc(num_questions+1,sizeof(char));
 1662:    for (num=0; num<num_questions; num++)  {
 1663:      log_string[num]='-';
 1664:      sscanf(entry.tries + 3*num,"%d,",&(tried[num]) );
 1665:    }
 1666:    log_string[num_questions]=0;
 1667:    capa_set_login_time(student_number,set);
 1668:    for (num=0,p=first_problem; p; ){
 1669:       if( start_from > 1 ) {
 1670:         num=start_from-1;
 1671:         for (p=first_problem; start_from > 1 && p->next; start_from--)
 1672:              p=p->next;
 1673:         start_from = 0;
 1674:       }
 1675:       if (display) {
 1676:          /* DISPLAY QUESTION */
 1677:          CLEAR();
 1678:          second_scr = display_prob_scr(p->question,scr_idx);
 1679:          allow_subj = 0;
 1680:          if( p->ans_type == ANSWER_IS_SUBJECTIVE ) {
 1681:            allow_subj = 1;
 1682:            move(A_ROW,A_COL); clrtoeol();
 1683:            mvaddstr(A_ROW,A_COL,"Enter :A to answer subjective question");
 1684:          }
 1685:          mvaddstr(S_ROW,0,"OPTION/ANSWER");
 1686:          mvaddstr(O_ROW,0,"Options :M = Main Menu  :7 = go to # 7");
 1687:          allow_n = allow_p = 0;
 1688:          if( second_scr && (scr_idx == 1) ) {
 1689:            mvaddstr(O_ROW,E_COL,":N = Next screen");
 1690:            allow_n=1;
 1691:          }
 1692:          if( second_scr && (scr_idx == 2) ) {
 1693:            mvaddstr(O_ROW,E_COL,":P = Prev screen");
 1694:            allow_p=1;
 1695:          }
 1696:          
 1697:          mvaddstr(O_ROW,R_COL,"RETURN = Enter/Execute");
 1698: 	 
 1699: 	 if (g_inhibit_response ) {
 1700: 	   canAnswer = show_prior_inhibited_response(p,header.partial_credit[num],entry.answers[num],tried[num],&allow_hint);
 1701: 	 } else {
 1702: 	   canAnswer = show_prior_response(p,header.partial_credit[num],entry.answers[num],tried[num],&allow_hint);
 1703: 	 }
 1704: 	 
 1705:       }
 1706:       mvaddstr(X_ROW,X_COL,":X = eXit");
 1707:       
 1708:       /* <= */
 1709:       
 1710:       
 1711:       
 1712:         get_xinput(S_ROW,A_COL,u_input,U_ANS_CHAR);
 1713:         display=0;  usr_command=C_DONTCARE;
 1714:         /* DEFAULT ACTIONS on empty input */
 1715:         if(!strlen(u_input)) { usr_command = (p->next? C_FORWARD : C_MENU); } else {
 1716:           if( u_input[0] == ':' ) {
 1717:            switch(toupper( u_input[1] )) {
 1718:              case 'H': if( allow_hint ) { usr_command=C_HINT; } break;
 1719:              case 'M': usr_command=C_MENU;    break;
 1720:              case 'N': if( allow_n ) { usr_command=C_NEXTSCR; } break;
 1721:              case 'P': if( allow_p ) { usr_command=C_PREVSCR; } break;
 1722:              case 'X': usr_command=C_EXIT;    break;
 1723:              case 'A': if( allow_subj ) { usr_command=C_SUBJANS; } break;
 1724:              default : sscanf(u_input,":%d",&whereto);
 1725:                     if(whereto >0 && whereto <= num_questions) usr_command=C_JUMP;
 1726: 		    break;
 1727:            }
 1728:           } else { /* user entered some answer */
 1729:             if( p->ans_op == ANS_AND ) {
 1730:               if(canAnswer) { usr_command=C_ANSWER;
 1731:                 ans_strs = (char **)capa_malloc(sizeof(char *), p->ans_cnt);
 1732:                 ans_strs[0] = (char *)capa_malloc(strlen(u_input)+1,1);
 1733:                 strcpy(ans_strs[0],u_input);
 1734:                 for(i=1;i<p->ans_cnt;i++) {
 1735:                   mvaddstr(A_ROW,A_COL,"                                ");
 1736: 	          mvaddstr(A_ROW,A_COL,ans_strs[i-1]);
 1737:                   sprintf(one_line,    " Entering answer %3d of %3d     ", i+1,p->ans_cnt);
 1738:                   mvaddstr(A_ROW,S_COL,one_line);
 1739:                   mvaddstr(S_ROW,A_COL,"                                ");
 1740:                   get_xinput(S_ROW,A_COL,u_input,U_ANS_CHAR);
 1741:                   ans_strs[i] = (char *)capa_malloc(strlen(u_input)+1,1);
 1742:                   strcpy(ans_strs[i],u_input);
 1743:                   
 1744:                 }
 1745:                 
 1746:                 /* now in ans_strs[][] are user inputs */
 1747:                 
 1748:               }
 1749:             } else { /* one answer or ANS_OR */
 1750:               ans_strs = (char **)capa_malloc(sizeof(char *), 1);
 1751:               ans_strs[0] = (char *)capa_malloc(strlen(u_input)+1,1);
 1752:               strcpy(ans_strs[0], u_input);
 1753:               if(canAnswer)  { usr_command=C_ANSWER; 
 1754: 	         mvaddstr(S_ROW,A_COL,"                                ");
 1755: 	         mvaddstr(A_ROW,A_COL,"                                ");
 1756: 	         mvaddstr(A_ROW,A_COL,ans_strs[0]);  }
 1757: 	    }
 1758:           } /* end if  u_input[0] == ':' */
 1759:         } /* end if !strlen(u_input) */
 1760:       
 1761:         
 1762:       
 1763:       
 1764:       
 1765:       /* PROCESS USER COMMAND */
 1766:       switch(usr_command) {
 1767:         case C_FORWARD: /* Forwards */
 1768:                 if (p->next) {
 1769:                    p=p->next; num++;
 1770:                    display=1; allow_hint=0; scr_idx=1;
 1771:                 } else
 1772:                    mvaddstr(X_ROW,R_COL,"RETURN = Main Menu   ");
 1773:                 break;
 1774:         case C_NEXTSCR:  scr_idx = 2; display=1;
 1775:                 break;
 1776:         case C_PREVSCR:  scr_idx = 1; display=1;
 1777:                 break;
 1778:         case C_EXIT: /* Exit */ 
 1779:                 ex=1; p=0; break;
 1780:         case C_MENU: /* Return to main menu */
 1781:                 p=0;  break;
 1782:         case C_HINT: /* Hint */
 1783:                 if (! p->hint)    break;
 1784:                 display_hint(p->hint);
 1785:                 display=1;
 1786:                 break;
 1787:         case C_ANSWER: /* Answer question */
 1788:               { 
 1789: 		if(p->ans_type== ANSWER_IS_SUBJECTIVE) {
 1790: 		  move(A_ROW,A_COL); clrtoeol();
 1791: 		  mvaddstr(A_ROW,A_COL,"Enter :A to answer subjective question");
 1792: 		  capa_mfree(ans_strs[0]);
 1793: 		  break;
 1794: 		}
 1795: 		if( p->ans_op == ANS_AND ) {
 1796: 		    leng = 0;
 1797: 		    for(i=0;i<p->ans_cnt;i++) {
 1798: 		       leng += (strlen((char *)ans_strs[i]) + 2);
 1799: 		    }
 1800: 		    a_str = (char *)capa_malloc(leng+1,1);
 1801: 		    a_str[0]=0;
 1802: 		    strcat(a_str,ans_strs[0]);
 1803: 		    if ( is_all_ws(ans_strs[0]) )  break;
 1804: 		    trim_response_ws(ans_strs[0]);
 1805: 		    for(i=1;i<p->ans_cnt;i++) {
 1806: 		       strcat(a_str,"\t");
 1807: 		       strcat(a_str,ans_strs[i]);
 1808: 		       if ( is_all_ws(ans_strs[i]) )  break;
 1809: 		       trim_response_ws(ans_strs[i]);
 1810: 		    }
 1811: 		    if (i < p->ans_cnt) {
 1812: 		      display=1; /*handle early breaks out of the*/
 1813: 		      break; 	 /*loop which mean typed only ws */
 1814: 		    }
 1815: 		} else { /* only one answer */
 1816: 		  leng = (strlen((char *)ans_strs[0]) + 2);
 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: 		}
 1823: 		
 1824: 		sprintf(submissions_str,"%d\t%s\t",num+1,a_str);
 1825: 		log_submissions(student_number,set,submissions_str);
 1826: 
 1827: 		{
 1828: 		  int cnt=((p->ans_op==ANS_AND)?p->ans_cnt:1);
 1829:      		  if (g_inhibit_response) {
 1830: 		    canAnswer = give_inhibited_response(p, ans_strs,cnt,
 1831: 							&(tried[num]),&log_char);
 1832: 		  } else {
 1833: 		    canAnswer = give_response(p, ans_strs,cnt, &(tried[num]),&log_char);
 1834: 		  }
 1835: 		}
 1836: 		if( p->ans_op == ANS_AND ) {
 1837: 		  for(i=0;i<p->ans_cnt;i++) {
 1838: 		    capa_mfree( (char *)ans_strs[i] );
 1839: 		  }
 1840: 		  
 1841: 		} else { /* there is only one user answer */
 1842: 		  capa_mfree( (char *)ans_strs[0] );
 1843: 		  
 1844: 		}
 1845: 		capa_mfree((char *)ans_strs);
 1846: 		capa_mfree( (char *)a_str );
 1847: 		
 1848:                 if (p->hint && 
 1849: 		    (
 1850: 		     (p->show_hint<=tried[num])||
 1851: 		     (log_char == 'y') ||
 1852: 		     (log_char == 'Y')
 1853: 		     )
 1854: 		    ){
 1855: 		  allow_hint=1;
 1856: 		  mvaddstr(X_ROW,H_COL,":H = Show Hint");
 1857:                 }
 1858:                 switch(log_char) {
 1859:                   case 'U': case 'u': case 'S': 
 1860:                             entry.answers[num]='N';      break;
 1861:                   case 'Y': allow_hint=1; mvaddstr(X_ROW,H_COL,":H = Show Hint");  /* fall through here */
 1862:                    default: entry.answers[num]=log_char; break;
 1863:                 }
 1864:                 log_string[num]=log_char;
 1865:                 
 1866:                 log_attempt(student_number,set,*section,log_string);
 1867:                 /* for (i=0; i<num_questions; i++) { log_string[i] = '-' ;  } */
 1868: 		set_entry_tries(tried,entry.tries,num,num_questions);
 1869: 		log_string[num]='-';
 1870:                 /* ------------------------------ check due date */
 1871:                 time(&curtime);
 1872:                 /* ===> if (compare_datetime(curtime,header.due_date) > 0) { */
 1873:                 if( capa_check_date(CHECK_DUE_DATE,student_number,*section,set) > 0 ) {
 1874:                   capa_get_date(CHECK_DUE_DATE,student_number,*section,set,date_str);
 1875:                   sprintf(answer,"Sorry, the due date was: %s",date_str);
 1876:                   move(20,1); clrtobot(); addstr(answer); mypause(23,1);
 1877:                 } else {
 1878:                   capa_set_entry(&entry,student_number,set,offset);
 1879:                 }
 1880:               } break;
 1881:         case C_JUMP: /* Jump to specific question number */
 1882:                 num=whereto-1;
 1883:                 for (p=first_problem; whereto > 1 && p->next; whereto--)
 1884:                    p=p->next;
 1885:                 display=1;  allow_hint=0; scr_idx=1;
 1886:                 break;
 1887:         case C_SUBJANS:  
 1888:                 answered=answer_subjective(student_number,set,section,num+1); 
 1889: 		if (answered) {
 1890: 		  tried[num]++;
 1891: 		  if (p->hint && ((p->show_hint<=tried[num]))) { allow_hint=1; }
 1892: 		  entry.answers[num]='0';
 1893: 		  log_string[num]='A';
 1894: 		  log_attempt(student_number,set,*section,log_string);
 1895: 		  log_string[num]='-';
 1896: 		  set_entry_tries(tried,entry.tries,num,num_questions);
 1897:                   capa_set_entry(&entry,student_number,set,offset);
 1898: 		}
 1899:                 display=1;
 1900:                 break;
 1901:         case C_DONTCARE:  break;
 1902:       }
 1903:    }
 1904:    for (i=0,j=0, num=0; num<num_questions; num++) {
 1905:      j = j + (header.weight[num] - '0');
 1906:      if((entry.answers[num]=='Y') || (entry.answers[num]=='y')) 
 1907:        i = i + (header.weight[num] - '0');
 1908:      if( entry.answers[num] >= '0' && entry.answers[num] <= '9' ) {
 1909:         i = i + (entry.answers[num] - '0');
 1910:      }
 1911:      if((entry.answers[num]=='E') || (entry.answers[num]=='e')) 
 1912:        j = j - (header.weight[num] - '0');
 1913:      if((tried[num] >=0) && (tried[num] <= TRY_BOUND) ) {
 1914:        if(tried[num] < 10 ) {
 1915:          entry.tries[3*num]   = ' ';
 1916:          entry.tries[3*num+1] = tried[num] + '0';
 1917:          if(num < num_questions-1)  entry.tries[3*num+2] = ',';
 1918:        } else {
 1919:          entry.tries[3*num]   = (int)(tried[num]/10) + '0';
 1920:          entry.tries[3*num+1] = (tried[num] % 10) + '0';
 1921:          if(num < num_questions-1)  entry.tries[3*num+2] = ',';
 1922:        }
 1923:      } else {
 1924:        entry.tries[3*num]   = ' ';
 1925:        entry.tries[3*num+1] = 1 + '0';
 1926:        if(num < num_questions-1)  entry.tries[3*num+2] = ',';
 1927:      }
 1928:    }
 1929:    capa_mfree(header.weight);
 1930:    capa_mfree(header.partial_credit);
 1931: 
 1932:    sprintf(answer,"Your score for this set is now: %d/%d",i,j);
 1933:    move(20,1); clrtobot(); addstr(answer); mypause(23,1);
 1934:    /* ------- original code , should check due date before save it
 1935:    
 1936:    time(&curtime);
 1937:    if (compare_datetime(curtime,header.due_date) > 0) {
 1938:    if( capa_check_date(CHECK_DUE_DATE,*section,set) > 0 ) {
 1939:       need to deal with due_date 
 1940:       sprintf(answer,"Sorry, the due date was: %s",header.due_date);
 1941:       move(20,1); clrtobot(); addstr(answer); mypause(23,1);
 1942:    } else {
 1943:       sprintf(answer,"Your score for this set is now: %d/%d",i,j);
 1944:       move(20,1); clrtobot(); addstr(answer); mypause(23,1);
 1945:       
 1946:       capa_set_entry(&entry,student_number,set,offset);
 1947:    }
 1948:    ------ */
 1949:    /* FREE UP MALLOC'ED SPACE (VERY IMPORTANT) */
 1950:    capa_mfree(entry.answers);
 1951:    capa_mfree(entry.tries);
 1952:    free_problems(first_problem);
 1953:    /* log_attempt(student_number,set,*section,log_string); */
 1954:    capa_mfree(log_string);
 1955:    capa_mfree((char*)tried);
 1956:    if (ex) properly_logout(student_number);
 1957:    
 1958: }
 1959: 
 1960: #define   COL_ONE    1
 1961: #define   COL_TWO    17
 1962: #define   COL_THREE  34
 1963: #define   COL_FOUR   43
 1964: #define   COL_FIVE   69
 1965: 
 1966: /* ------------------------------------------------------------------------- */
 1967: /* REVIEW PREVIOUS PROBLEM SETS                                              */
 1968: /* ------------------------------------------------------------------------- */
 1969: void                                      /* RETURNS: (nothing)              */
 1970: view_previous(student_number,set,section) /* ARGUMENTS:                      */
 1971: char  *student_number;                    /*    Student number               */
 1972: int  set;                                 /*    Set number                   */
 1973: int *section;                             /*    Section number               */
 1974: {                                         /* LOCAL VARIABLES:                */
 1975:    T_entry   entry;                       /*    Database entry               */
 1976:    Problem_t *first_problem,              /*    Pointer to first problem     */
 1977:              *problem;                    /*    Previous problem             */
 1978:    int        num_questions,              /*    Total # of questions         */
 1979:               ex=0,                       /*    Exit system flag             */
 1980:               display=1,                  /*    Redraw flag                  */
 1981: 	      usr_command,
 1982: 	      whereto, 
 1983: 	      allow_hint=0, allow_explain=0;
 1984:    int        num;                        /*    Temporary variable           */
 1985:    char       buf[4],                     /*    Command input buffer         */
 1986:               aLine[MAX_BUFFER_SIZE];
 1987:    T_header   header;                     /*    Set header                   */
 1988:    time_t     curtime;                    /*    Current time                 */
 1989:    double     upper_ans;
 1990:    char       fmt_ans[ANSWER_STRING_LENG], goto_str[ANSWER_STRING_LENG], 
 1991:               tmp_str[ANSWER_STRING_LENG];
 1992:    int        scr_idx=1, second_scr, allow_n, allow_p;
 1993:    
 1994:    /* QUERY USER FOR SET */
 1995:    move(15,5);  /* deleteln(); */
 1996:    addstr("            Which set would you like to view?");
 1997:    mvaddstr(16,15,   "Enter a set number and press ENTER/RETURN");
 1998:    move(17,1); clrtoeol(); /* erase Enter a command ... */
 1999:    do { get_input(15,51,buf,3); } while(!strlen(buf));
 2000:    sscanf(buf,"%d",&num);
 2001:    if (num<1 || num>set) {
 2002:       move(17,5); clrtoeol();
 2003:       mvaddstr(17,15,"   Error: Invalid previous set number\n");
 2004:       mypause(19,17);   return;
 2005:    }
 2006:    /* ------------------------------------ answer date */
 2007:    time(&curtime);
 2008:    /* ===> if (compare_datetime(curtime,header.answer_date) < 0) { */
 2009:    if ( capa_check_date(CHECK_ANS_DATE,student_number,*section,num) < 0 ) {
 2010:       move(16,1); clrtoeol();
 2011:       move(17,5); clrtoeol();
 2012:       mvaddstr(17,15,"  Answers are not yet available\n");  mypause(19,17);  return;
 2013:    }
 2014: 
 2015:    /* LOAD IN THE INFO NEEDED */
 2016:    capa_get_header(&header,num);
 2017:    capa_get_entry(&entry,student_number,num);
 2018:    capa_parse(num,&first_problem,student_number,&num_questions,NULL);
 2019:    sprintf(goto_str,"#=go to problem #, [%d problems]", num_questions);
 2020:    for (num=0,problem=first_problem; problem; ) {
 2021:       if (display) {
 2022:          allow_hint = allow_explain=0;
 2023:          allow_n = allow_p = 0;
 2024:          CLEAR();
 2025:          second_scr = display_prob_scr(problem->question,scr_idx);
 2026:          if( problem->ans_type == ANSWER_IS_FLOAT ) {
 2027:              upper_ans = (double)atof(problem->answer);
 2028:              sprintf(fmt_ans, problem->ans_fmt, upper_ans);
 2029:          } else {
 2030:              sprintf(fmt_ans, "%s", problem->answer);
 2031:          }
 2032:          if( problem->ans_unit ) {
 2033:              sprintf(tmp_str, "Answer: %s %s",fmt_ans,problem->unit_str);
 2034:          } else {
 2035:              sprintf(tmp_str, "Answer: %s",fmt_ans);
 2036:          }
 2037:          mvaddstr(S_ROW,COL_ONE,tmp_str);
 2038:          
 2039:          switch(entry.answers[num]) {
 2040:            case 'Y': mvaddstr(S_ROW,COL_FOUR,"CORRECT         "); break;
 2041:            case 'y': mvaddstr(S_ROW,COL_FOUR,"HANDIN CORRECT  "); break;
 2042:            case '-': mvaddstr(S_ROW,COL_FOUR,"UNANSWERED      "); break;
 2043:            case 'e': mvaddstr(S_ROW,COL_FOUR,"EXCUSED         "); break;
 2044:            case 'E': mvaddstr(S_ROW,COL_FOUR,"EXCUSED         "); break;
 2045:            case 'n': mvaddstr(S_ROW,COL_FOUR,"HANDIN INCORRECT"); break;
 2046:            case 'N': mvaddstr(S_ROW,COL_FOUR,"INCORRECT       "); break;
 2047:            default : if(entry.answers[num] >= '0' && entry.answers[num] <= '9') {
 2048:                       sprintf(aLine,"HAND-GRADED %c/%c ",entry.answers[num],
 2049: 			      header.weight[num]);
 2050:                       mvaddstr(S_ROW,COL_FOUR,aLine);
 2051:                      }
 2052:                      break;
 2053:          }
 2054:          mvaddstr(S_ROW,COL_FIVE,"OPTION:");
 2055:          
 2056:          mvaddstr(O_ROW,COL_ONE,"M=Main menu");
 2057:          if( second_scr && scr_idx == 1) {
 2058:            mvaddstr(O_ROW,COL_TWO,"N=Next screen");
 2059:            allow_n = 1;
 2060:          }
 2061:          if( second_scr && scr_idx == 2) {
 2062:            mvaddstr(O_ROW,COL_TWO,"P=Prev screen");
 2063:            allow_p = 1;
 2064:          }
 2065:          mvaddstr(O_ROW,COL_THREE,"X=eXit");
 2066:          mvaddstr(O_ROW,COL_FOUR, "RETURN=Enter/Execute");
 2067:          if ( problem->hint && 
 2068: 	      ( 
 2069: 	       (problem->show_hint <= problem->tries) || 
 2070: 	       (entry.answers[num] == 'Y') || 
 2071: 	       (entry.answers[num] == 'y')
 2072: 	       ) 
 2073: 	      )    { 
 2074: 	   allow_hint=1;    mvaddstr(O_ROW,COL_FIVE,"H=Hint"); 
 2075: 	 }
 2076:          mvaddstr(X_ROW,COL_ONE,goto_str);
 2077:          if (problem->next)
 2078:                mvaddstr(X_ROW,COL_FOUR,"RETURN=next problem");
 2079:             else
 2080:                mvaddstr(X_ROW,COL_FOUR,"RETURN=main menu   ");
 2081:          if ( problem->explain ) { allow_explain=1; mvaddstr(X_ROW,COL_FIVE,"E=Explain"); }
 2082:    
 2083:       }
 2084:       get_input(S_ROW,COL_FIVE+7,buf,3);
 2085:       display=0; usr_command=C_DONTCARE;
 2086:       /* DEFAULT ACTIONS on empty input */
 2087:       if(!strlen(buf)) { usr_command = (problem->next? C_FORWARD : C_MENU); } else {
 2088:         switch(toupper(buf[0])) {
 2089:          case 'X': usr_command=C_EXIT;    break;
 2090:          case 'M': usr_command=C_MENU;    break;
 2091: 	 case 'H': usr_command=C_HINT;    break;
 2092:          case 'E': usr_command=C_EXPLAIN; break;
 2093:          case 'N': if( allow_n ) { usr_command=C_NEXTSCR; } break;
 2094:          case 'P': if( allow_p ) { usr_command=C_PREVSCR; } break;
 2095:          default : sscanf(buf,"%d",&whereto);
 2096:                   if(whereto >0 && whereto <= num_questions) usr_command=C_JUMP;
 2097: 		  break;
 2098:         }
 2099:       }
 2100: 
 2101: 
 2102:       /* PROCESS USER COMMAND */
 2103:       switch(usr_command) {
 2104:       case C_FORWARD: /* FORWARDS ONE */
 2105:                 if (problem->next) {
 2106:                    problem=problem->next; display=1; scr_idx = 1; num++;
 2107:                 } else
 2108:                    mvaddstr(X_ROW,COL_FOUR,"RETURN=main menu   ");
 2109:                 break;
 2110:       case C_HINT: /* HINT */
 2111:                 if(allow_hint) {
 2112:                   display_hint(problem->hint);
 2113:                   display=1;
 2114:                   allow_hint = 0;
 2115:                 }
 2116: 		break;
 2117:       case C_EXPLAIN: /* Explain */
 2118:                 if(allow_explain) {
 2119:                   display_hint(problem->explain); display=1;
 2120: 		  allow_explain=0;
 2121: 		}
 2122: 		break;
 2123:       case C_NEXTSCR:  scr_idx = 2; display=1;
 2124:                 break;
 2125:       case C_PREVSCR:  scr_idx = 1; display=1;
 2126:                 break;
 2127:       case C_EXIT: /* EXIT SYSTEM */
 2128:                 ex=1; problem=0; break;
 2129: 
 2130:       case C_MENU: /* RETURN TO MAIN MENU */
 2131:                 problem=0;  break;
 2132: 
 2133:       case C_JUMP: /* JUMP TO SPECIFIC PROBLEM # */
 2134:                    num=whereto-1;
 2135:                    for (problem=first_problem; whereto > 1 && problem->next; whereto--)
 2136:                       problem=problem->next;
 2137:                    display=1;
 2138:                    scr_idx = 1;
 2139:                  break;
 2140:       case C_TIME:     break;
 2141:       case C_DONTCARE: break;
 2142:       }
 2143:    }
 2144: 
 2145:    /* FREE UP MALLOC'ED SPACE - VERY IMPORTANT */
 2146:    capa_mfree(header.weight);
 2147:    capa_mfree(header.partial_credit);
 2148:    capa_mfree(entry.answers);
 2149:    capa_mfree(entry.tries);
 2150:    free_problems(first_problem);
 2151: 
 2152:    if (ex) properly_logout(student_number);
 2153: }
 2154: 
 2155: /* -------------------------------------------------------------------------- */
 2156: /* DISPLAY HELP SCREEN                                                        */
 2157: /* -------------------------------------------------------------------------- */
 2158: void                  /* RETURNS: (nothing)      */
 2159: display_help()        /* ARGUMENTS: (none)       */
 2160: {                     /* LOCAL VARIABLES:        */
 2161:    FILE *fp;          /*    Welcome file pointer */
 2162:    char  buf[255];    /*    Input buffer         */
 2163: 
 2164:    CLEAR();
 2165:    if ((fp=fopen("help.msg","r"))!=NULL) {
 2166:       while (fgets(buf,255,fp))  addstr(buf);
 2167:       fclose(fp);
 2168:    }
 2169:    mypause(22,20);
 2170: }
 2171: 
 2172: 
 2173: /*   A class directory must have   */
 2174: /*     records/                    */
 2175: /*                                 */
 2176: /*  returns: 0  structure is correct, but no set.db files */
 2177: /*          -1  structure is not correct                  */
 2178: /*          >=1 the last set.db                           */
 2179: 
 2180: int
 2181: check_class_get_set(dir_path) char  *dir_path;
 2182: {
 2183:   char   f_name[1024];
 2184:   int    set;
 2185:   
 2186:   if( capa_access(dir_path, F_OK) == 0 ) { /* class dir exists */
 2187:     sprintf(f_name,"%s/records",dir_path);
 2188:     if( capa_access(f_name, F_OK) == 0 ) { /* class/records dir exists */
 2189:       for(set = 1; ; set++ ) {
 2190:         sprintf(f_name,"%s/records/set%d.db",dir_path,set);
 2191:         if(capa_access(f_name, F_OK) == -1 )  break;
 2192:       }
 2193:       set--;
 2194:     } else {
 2195:       set = -1;
 2196:     }
 2197:   } else {
 2198:     set = -1;
 2199:   } 
 2200:   return (set);
 2201: }
 2202: /* -------------------------------------------------------------------------- */
 2203: /* Get Exam and Quiz Path                                                     */
 2204: /*   return  0, 1, 2, 3         */
 2205: /* -------------------------------------------------------------------------- */
 2206: int
 2207: check_exam_quiz_f()
 2208: {
 2209:    char  buf[MAX_BUFFER_SIZE];
 2210:    int   result = 0, configResult=0;
 2211: 
 2212: #ifdef LOGIN_DBUG
 2213:    fprintf(dfp,"CHECK EXAM Access() success,and open(),%s\n",buf); fflush(dfp);
 2214: #endif
 2215:    configResult=read_capa_config("exam_path",buf);
 2216:    if (configResult != 0 && configResult != -1) {
 2217:      Exam_set = check_class_get_set(buf);
 2218:      if(Exam_set > 0 )  {
 2219:        result = 1;
 2220:        sprintf(Exam_path,buf);
 2221:      }
 2222:    }
 2223: #ifdef LOGIN_DBUG
 2224:    fprintf(dfp,"CHECK EXAM = %d,%s\n", result,Exam_path); fflush(dfp);
 2225: #endif
 2226:    configResult=read_capa_config("quiz_path",buf);
 2227:    if (configResult != 0 && configResult != -1) {
 2228:      Quiz_set = check_class_get_set(buf);
 2229:      if(Quiz_set > 0 )  {
 2230:        result = (result | 2);
 2231:        sprintf(Quiz_path,buf);
 2232:      }
 2233:    }
 2234:    
 2235:    return (result);
 2236: }
 2237: 
 2238: /* -------------------------------------------------------------------------- */
 2239: /* DISPLAY MAIN MENU                                                          */
 2240: /* -------------------------------------------------------------------------- */
 2241: void                  /* RETURNS: (nothing) */
 2242: display_menu(student, exam_f, quiz_f) 
 2243: T_student *student;
 2244: int        exam_f, quiz_f;
 2245: {
 2246:    char buff[MAX_BUFFER_SIZE];
 2247:    int  c_y,configResult,term_summary_button=1;
 2248:    
 2249:    configResult=read_capa_config("term_summary_button",buff);
 2250:    if (configResult != 0 && configResult != -1 ) {
 2251:      if (strcasecmp(buff,"no")==0) {
 2252:        term_summary_button=0;
 2253:      }
 2254:    }
 2255: 
 2256:    CLEAR();
 2257: 
 2258:    mvaddstr(1,10,student->s_nm);
 2259:    sprintf(buff,"Section: %d",student->s_sec);
 2260:    mvaddstr(1,50,buff);
 2261: 
 2262:    mvaddstr( 4,25,"  MAIN MENU"); c_y = 6;
 2263:    mvaddstr( c_y,25,"H=Help");    c_y++;
 2264:    if (term_summary_button) { mvaddstr( c_y,25,"S=Summary"); c_y++; }
 2265:    mvaddstr( c_y,25,"T=Try set"); c_y++;
 2266:    mvaddstr( c_y,25,"V=View previous set"); c_y++;
 2267:    if(exam_f) { mvaddstr( c_y,25,"E=view Exam summary"); c_y++; }
 2268:    if(quiz_f) { mvaddstr( c_y,25,"Q=view Quiz summary"); c_y++; }
 2269:    mvaddstr( c_y,25,"X=eXit system");
 2270: 
 2271:    mvaddstr(14,25,"COMMAND:");
 2272: 
 2273:    mvaddstr(17, 5,"Enter a command from the list above and press ENTER/RETURN");
 2274: }
 2275: 
 2276: /* -------------------------------------------------------------------------- */
 2277: /* CONTROL MAIN MENU SELECTIONS                                               */
 2278: /* -------------------------------------------------------------------------- */
 2279: void                                    /* RETURNS: (nothing)     */
 2280: menu_main(student_number,set,section)   /* ARGUMENTS:             */
 2281: char *student_number;                   /*    Student number      */
 2282: int set;                                /*    Set number          */
 2283: int section;                            /*    Section number      */
 2284: {                                       /* LOCAL VARIABLES:       */
 2285:    int       ex=0,                      /*    Exit system flag    */
 2286:              cmd;                       /*    User command        */
 2287:    char      buff[MAX_BUFFER_SIZE];     /*    User command buffer */
 2288:    T_student a_student;
 2289:    int       had_exam, had_quiz, outcome,configResult;
 2290: 
 2291: #ifdef LOGIN_DBUG
 2292:    fprintf(dfp,"MENU in %s sec=%d\n", student_number,section); fflush(dfp);
 2293: #endif
 2294: 
 2295:    outcome = check_exam_quiz_f();
 2296:    had_exam = outcome & 1;
 2297:    had_quiz = outcome & 2;
 2298: 
 2299: #ifdef LOGIN_DBUG
 2300:    fprintf(dfp,"After check %d\n", outcome); fflush(dfp);
 2301: #endif
 2302: 
 2303:    capa_get_student(student_number,&a_student);
 2304:    
 2305:    g_inhibit_response=capa_check_option(OPTION_INHIBIT_RESPONSE,set,section);
 2306:    if (g_inhibit_response < 0 ) g_inhibit_response=0;
 2307: 
 2308:    display_menu(&a_student,had_exam, had_quiz);
 2309:    while (!ex) {
 2310:       do {
 2311:          buff[0] = ' '; buff[1] = 0;
 2312:          get_input(14,34,buff,1);  cmd=toupper(buff[0]);
 2313:       } while (isspace(cmd));
 2314:       move(14,35); clrtoeol();
 2315:       /* PROCESS USER COMMAND */
 2316:       switch(cmd) {
 2317: 
 2318:       case 'H': /* DISPLAY HELP */
 2319:                 display_help();
 2320:                 display_menu(&a_student,had_exam, had_quiz);
 2321:                 break;
 2322:  
 2323:       case 'T': /* TRY CURRENT SET */
 2324:                 try_set(student_number,set,&section);       
 2325:                 display_menu(&a_student,had_exam, had_quiz);
 2326:                 break;
 2327: 
 2328:       case 'V': /* VIEW PREVIOUS SET */
 2329:                 view_previous(student_number,set,&section); 
 2330:                 display_menu(&a_student,had_exam, had_quiz);
 2331:                 break;
 2332: 
 2333:       case 'S': /* DISPLAY TERM SUMMARY */
 2334: 	        configResult=read_capa_config("term_summary_button",buff);
 2335: 		if (configResult != 0 && configResult != -1 ) {
 2336: 		  if ((strcasecmp(buff,"no")==0)) {
 2337: 		    break;
 2338: 		  }
 2339: 		}
 2340: 		term_summary(student_number,set,&section,TERM_SUMMARY);  
 2341: 		display_menu(&a_student,had_exam, had_quiz);
 2342: 		break;
 2343:       case 'E': /* VIEW EXAM SUMMARY */
 2344:                 if( had_exam ) {
 2345:                   chdir(Exam_path);
 2346:                   term_summary(student_number,Exam_set,&section,EXAM_SUMMARY);  
 2347:                   display_menu(&a_student,had_exam, had_quiz);
 2348:                   chdir(Orig_path);
 2349:                 }
 2350:                 break;
 2351:       case 'Q': /* VIEW QUIZ SUMMARY */
 2352:                 if( had_quiz ) {
 2353:                   chdir(Quiz_path);
 2354:                   term_summary(student_number,Quiz_set,&section,QUIZ_SUMMARY);  
 2355:                   display_menu(&a_student,had_exam, had_quiz);
 2356:                   chdir(Orig_path);
 2357:                 }
 2358:                 break;
 2359:       case EOF: /* EXIT SYSTEM */
 2360:       case 'X': ex=1; break;
 2361: 
 2362:       default:  /* INVALID COMMAND */
 2363:                 /* printf("Invalid choice\n"); */
 2364:                 break;
 2365:       }
 2366:    }
 2367: }
 2368: 
 2369: /* -------------------------------------------------------------------------- */
 2370: /* DISPLAY WELCOME MESSAGE WHEN USER LOGS IN                                  */
 2371: /* -------------------------------------------------------------------------- */
 2372: void               /* RETURNS: (nothing)      */
 2373: welcome()          /* ARGUMENTS:         */
 2374: {                  /* LOCAL VARIABLES:        */
 2375:    FILE *fp;       /*    Welcome file pointer */
 2376:    char  buf[TMP_LINE_LENGTH]; /*    Input buffer         */
 2377: 
 2378:    CLEAR();
 2379:    /* sprintf(buf,"This is your %d-time login to this set, good luck!",tries);
 2380:    addstr(buf);
 2381:    */
 2382:    if ((fp=fopen("welcome.msg","r"))!=NULL) {
 2383:       while (fgets(buf,TMP_LINE_LENGTH-1,fp)) addstr(buf);
 2384:       fclose(fp);
 2385:    }
 2386: }
 2387: 
 2388: void print_version()
 2389: {
 2390:   printf("capalogin\n");
 2391:   printf("       CAPA version %s, %s\n",CAPA_VER,COMPILE_DATE);
 2392: }
 2393: 
 2394: /* ------------------------------------------------------------------------- */
 2395: /* DRIVER: INITIALIZE AND GO TO LOGIN                                        */
 2396: /* ------------------------------------------------------------------------- */
 2397: int
 2398: main(int argc, char **argv)
 2399: {                            /* LOCAL VARIABLES:            */
 2400:    char     student_number[MAX_STUDENT_NUMBER+1]; /* Student number         */
 2401:    int      set,             /*    Set number               */
 2402:             section=0,       /*    Section number           */
 2403:             result;          /* stores result from read_capa_config */
 2404:    char     filename[FILE_NAME_LENGTH];   /*    Question filename buffer */
 2405: #if defined(NeXT)
 2406:    char     cwd[FILE_NAME_LENGTH];
 2407: #endif
 2408:    char *class_path, buf[MAX_BUFFER_SIZE],*tty;
 2409:    
 2410:    
 2411:    if (argc > 1) { if (strcmp(argv[1],"-v") == 0) {print_version(); exit(0); } }
 2412: #ifdef LOGIN_DBUG
 2413:    printf("Create login.DBUG file:: argc = %d\n",argc);
 2414:    sprintf(filename,"login.DBUG");
 2415:    if ((dfp=fopen(filename,"a"))==NULL) { printf("Error: can't open login debug\n"); return; }
 2416: #endif /* LOGIN_DBUG */
 2417:    /* GET CURRENT SET NUMBER */
 2418:   for(set = 1; ; set++ ) {
 2419:     sprintf(filename,"set%d.qz",set);
 2420:     if(capa_access(filename, F_OK) == -1 )   break;
 2421:   }
 2422:   set--;
 2423: #if defined(NeXT) 
 2424:    class_path = getwd(cwd);
 2425:    if( class_path ==  NULL ) class_path = cwd;
 2426: #else
 2427:    class_path = getcwd(NULL,512);
 2428:    
 2429: #endif 
 2430:    sprintf(Orig_path,"%s",class_path);
 2431:    free(class_path);
 2432:    /* ---------------------------------------------- CURSES INITIALIZATION */
 2433:    signal(SIGINT , kick_out);
 2434:    signal(SIGALRM, kick_out);
 2435:    signal(SIGFPE, SIG_IGN);
 2436:    initscr(); savetty(); cbreak(); noecho();
 2437:    time(&log_in_time);
 2438:    strncpy(in_t,ctime(&log_in_time),31);
 2439:    in_t[ strlen(in_t)-1 ]=0;    /* Trash newline */
 2440:    tty=ttyname(0);
 2441:    if ( tty == NULL ) {
 2442:      strcpy(in_tty,"UNKNOWN");
 2443:    } else {
 2444:      strcpy(in_tty,tty);
 2445:    }
 2446:    result=read_capa_config("capalogin_goodbye_delay",buf);
 2447:    if (result != 0 && result != -1) {
 2448:      g_delay=atoi(buf);
 2449:    } else {
 2450:      g_delay=5;
 2451:    }
 2452:    result=read_capa_config("capalogin_inactivity_delay",buf);
 2453:    if (result != 0 && result != -1) {
 2454:      g_max_delay=atoi(buf);
 2455:    } else {
 2456:      g_max_delay=60;
 2457:    }
 2458:    welcome();
 2459:    strcpy(student_number, login(&set,&section)); student_number[MAX_STUDENT_NUMBER] = 0;
 2460: #ifdef LOGIN_DBUG
 2461:    fprintf(dfp,"login return:SNum=%s, set=%d, sec=%d\n", student_number,set, section); fflush(dfp);
 2462: #endif
 2463:    menu_main(student_number,set,section);
 2464: #ifdef LOGIN_DBUG
 2465:    fclose(dfp);
 2466: #endif
 2467:    properly_logout(student_number);
 2468:    return 0;
 2469: }
 2470: 

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