File:  [LON-CAPA] / capa / capa51 / pProj / capalogin.c
Revision 1.3: download - view: text, annotated - select for diffs
Mon Nov 8 22:30:02 1999 UTC (24 years, 7 months ago) by albertel
Branches: MAIN
CVS tags: HEAD
- changed default to not allow viewing between answd and due
- added debug to scorer for when it won't quit
- fixed problems with blank question bodies in capasbin
- fixed displaying of answer boxes to work with mixed /AND questions
- fixed summary screens in both capalogin and capaweb to work, so that
  non opened sets are not summaried
- fixed equation answers, so they can take array arguments for the
  point specifications

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

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