File:  [LON-CAPA] / capa / capa51 / pProj / capalogin.c
Revision 1.5: download - view: text, annotated - select for diffs
Fri Jun 30 21:36:16 2000 UTC (24 years, 1 month ago) by albertel
Branches: MAIN
CVS tags: HEAD
- gave everyone the GPL header

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

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