Annotation of capa/capa51/pProj/capalogin.c, revision 1.10

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

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