File:  [LON-CAPA] / capa / capa51 / pProj / capalogin.c
Revision 1.9: download - view: text, annotated - select for diffs
Thu Sep 14 20:24:44 2000 UTC (23 years, 8 months ago) by albertel
Branches: MAIN
CVS tags: HEAD
-a dded option to turn off date checking

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

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