/* main code that implements the capa login shell Copyright (C) 1992-2000 Michigan State University The CAPA system is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The CAPA system is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the CAPA system; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, you have permission to link this program with the TtH/TtM library and distribute executables, as long as you follow the requirements of the GNU GPL in regard to all of the software in the executable aside from TtH/TtM. */ /* version 4.6 */ /* Jan 28 1997 I.T. */ /* July 23 1998 I.T. */ #ifdef NeXT #include #include #include #else #include double atof(); #endif #include #ifdef TRUE #undef TRUE #endif #ifdef FALSE #undef FALSE #endif #include #if defined(__alpha) || defined(linux) #ifdef LOGIN_DBUG #define NO_PIN #define NO_DATE_CHECK #define NO_DUP_CHECK #endif #include #else #if defined(__sun) || defined(hpux) || defined(AIX) || defined(IRIX) #include /* #include */ #include /* MAXFLOAT */ #else #include #endif #endif #include #include #include #include #include #include "capaToken.h" #include "capaParser.h" #include "capaCommon.h" FILE *dfp; #define TERM_SUMMARY 1 #define EXAM_SUMMARY 2 #define QUIZ_SUMMARY 3 #define TRY_BOUND 99 #define TYR_SET_MENU_MACRO(xxx) { \ sprintf(aLine,"Total %d problems", num_questions); \ if(xxx) { \ mvaddstr(20,1,"Enter command M, A, #, T, or X."); mvaddstr(20,67,"COMMAND:"); \ mvaddstr(21,1,"M=go to Main Menu A=Answer T=Time RETURN=execute command"); \ } else { \ mvaddstr(20,1,"Enter command M, #, T, or X. "); mvaddstr(20,67,"COMMAND:"); \ mvaddstr(21,1,"M=go to Main Menu T=Time RETURN=execute command"); \ } \ mvaddstr(22,1, "#=go to problem # X=eXit CAPA"); \ mvaddstr(23,1,aLine); } #define REVIEW_SET_MENU_MACRO() { \ sprintf(aLine,"Total %d problems", num_questions); \ mvaddstr(20,1,"Enter command M, #, or X."); mvaddstr(20,67,"COMMAND:"); \ mvaddstr(21,1,"M=go to Main Menu RETURN=execute command"); \ mvaddstr(22,1,"#=go to problem # X=eXit CAPA"); \ mvaddstr(23,1,aLine); } #define TYRSET_MENU( ) { \ mvaddstr(22,0,"Commands :M = Main Menu :7 = go to Problem 7 RETURN = Enter/Execute"); \ } #define REVIEW_SET_MENU_MACRO() { \ sprintf(aLine,"Total %d problems", num_questions); \ mvaddstr(20,1,"Enter command M, #, or X."); mvaddstr(20,67,"COMMAND:"); \ mvaddstr(21,1,"M=go to Main Menu RETURN=execute command"); \ mvaddstr(22,1,"#=go to problem # X=eXit CAPA"); \ mvaddstr(23,1,aLine); } #define DBUG_TSUMMARY 0 #define CLEAR() clear(); refresh() #define ADDCH(c) addch(c); refresh() #define CLRTOEOL() clrtoeol(); refresh() #define CR 13 #define LF 10 #define SCREEN_BUFFER_SIZE 2048 time_t log_in_time, log_out_time; char in_t[32], in_tty[32]; char Orig_path[FILE_NAME_LENGTH], Exam_path[FILE_NAME_LENGTH], Quiz_path[FILE_NAME_LENGTH]; int Exam_set, Quiz_set; int g_inhibit_response; int g_delay; /* delay when logging out */ int g_max_delay; /* max number of minutes to wait for input, kick_out() after this much time */ /* Note: be careful to free entry answers */ /* ------------------------------------------------------------------------- */ /* WRITE OUTPUT (NICELY) TO THE SCREEN */ /* ------------------------------------------------------------------------- */ void /* RETURNS: (nothing) */ wrap(str) /* ARGUMENTS: */ char *str; /* Block of text to output */ { /* LOCAL VARIABLES: */ int y,x,len; /* Row,Col of screen */ int i, /* Next space */ j; /* Next char to print */ len=strlen(str); for (i=j=0; i 78) addch('\n'); while (j<=i) addch(str[j++]); } } int total_lines(char *str) { int len, lines_cnt=1; int i, j, x=0; len=strlen(str); for(i=j=0;i 78) { lines_cnt++; x = 0; } while (j<=i) { x++; if(str[j] == '\n') {lines_cnt++; x=0; } j++; } } return (lines_cnt); } /* --------------------------------------------- */ /* */ #define LINES_PER_SCREEN 20 int display_prob_scr(char *str,int scr_idx) { int len, lines_cnt=0; int i,j,y=0,x=0; int break_pt, onscreen_pr; int second_scr=0; if( str != NULL ) { lines_cnt = total_lines(str); if( lines_cnt > LINES_PER_SCREEN ) { second_scr = 1; } else { scr_idx = 1; } if( scr_idx == 1 ) { break_pt = LINES_PER_SCREEN + 1; } else { /* which line to break the problem text into two screens */ if(lines_cnt>=40) { break_pt = LINES_PER_SCREEN; } else { if(lines_cnt==39) { break_pt = LINES_PER_SCREEN - 1; } else { if(lines_cnt==38) { break_pt = LINES_PER_SCREEN - 2; } else { break_pt = LINES_PER_SCREEN - 3; } } } } #ifdef LOGIN_DBUG fprintf(dfp,"DISPLAY SCR IDX=%d total LineCnt=%d Line Break= %d:\n",scr_idx,lines_cnt,break_pt); fflush(dfp); #endif /* start to display the text on screen */ lines_cnt = 1; x = y =0; len=strlen(str); #ifdef LOGIN_DBUG fprintf(dfp,"SCR IDX=%d,leng=%d[[\n",scr_idx,len); fflush(dfp); #endif for(i=j=0;i break_pt) && (lines_cnt <= (break_pt+LINES_PER_SCREEN))) ) { getyx(stdscr,y,x); /* if (x2>=x) x=x2; else x=x2+80;*/ } while (i 78) { /* line break */ if( (scr_idx==1) && (lines_cnt < break_pt) ) { addch('\n'); onscreen_pr = 1; #ifdef LOGIN_DBUG fprintf(dfp,"\n[LineCnt=%d,x=%d,i=%d,j=%d]",lines_cnt,x,i,j); #endif } if( (scr_idx==2) && (lines_cnt > break_pt) && (lines_cnt <= (break_pt+LINES_PER_SCREEN)) ) { addch('\n'); onscreen_pr = 1; #ifdef LOGIN_DBUG fprintf(dfp,"\n[LineCnt=%d,x=%d,i=%d,j=%d]",lines_cnt,x,i,j); #endif } lines_cnt++; if(onscreen_pr == 0 ) { x=0; } } while (j<=i) { /* display on screen */ onscreen_pr = 0; if( (scr_idx==1) && (lines_cnt < break_pt) ) { addch(str[j]); /* display that character */ onscreen_pr = 1; #ifdef LOGIN_DBUG fprintf(dfp,"%c",str[j]); #endif } if( (scr_idx==2) && (lines_cnt > break_pt) && (lines_cnt <= (break_pt+LINES_PER_SCREEN)) ) { addch(str[j]); onscreen_pr = 1; #ifdef LOGIN_DBUG fprintf(dfp,"%c",str[j]); #endif } if( str[j] == '\n' ) { #ifdef LOGIN_DBUG fprintf(dfp,"[j=%d]",lines_cnt,j); #endif if(onscreen_pr == 0 ) { x = 0; } lines_cnt++; } if(onscreen_pr == 0 ) { x++; } j++; } } #ifdef LOGIN_DBUG fprintf(dfp,"\n]]"); fflush(dfp); #endif } return (second_scr); } /* ------------------------------------------------------------------------- */ /* DISPLAY FAREWELL MESSAGE WHEN USER GOT KICKED OUT */ /* ------------------------------------------------------------------------- */ void /* RETURNS: (nothing) */ #ifdef __sun kick_out(int sig) #else kick_out() #endif { /* LOCAL VARIABLES: */ FILE *fp; /* Goodbye file pointer */ char buf[255]; /* Input buffer */ /* DISPLAY EXIT MESSAGE */ CLEAR(); if ((fp=fopen("goodbye.msg","r"))!=NULL) { while (fgets(buf,255,fp)) addstr(buf); fclose(fp); } sprintf(buf, "This message will last for only %d seconds.",g_delay); mvaddstr(22,20,buf); refresh(); sleep(g_delay); /* mypause(22,20); */ /* CURSES RESTORATION */ resetty(); endwin(); exit(1); } /* ------------------------------------------------------------------------- */ /* GET INPUT (NICELY) FROM A PLACE ON THE SCREEN */ /* ------------------------------------------------------------------------- */ void /* RETURNS: (nothing) */ get_input(y,x,str,inmax) /* ARGUMENTS: */ int y,x; /* Row,Col of screen to start */ char *str; /* String buffer to fill in */ int inmax; /* Maximum number of characters */ { /* LOCAL VARIABLES: */ int i=0,cx,cy; /* Position in buffer */ char c; /* Input character */ if (y && x) move(y,x); CLRTOEOL(); cx = x; cy = y; #if defined( __alpha) || defined(__sun) while (1) { alarm(g_max_delay*60); c=getch(); if (c==10 || c==13) break; else if (c==8 || c==16 || c==127) { if (i>0) { i--; cx--; echo(); move(cy,cx); delch(); insch(' '); refresh(); noecho(); } else beep(); } else if (i>=inmax) { beep(); } else { str[i++] = c; cx++; echo(); ADDCH(c); noecho(); } } #else while (1) { alarm(g_max_delay*60); c=getch(); if (c==10 || c==13) break; else if (c==8 || c==16 || c==127) { if (i>0) { i--; printf("%c %c",8,8); refresh(); } else printf("%c",7); } else if (i>=inmax) { printf("%c",7); } else { str[i++] = c; ADDCH(c); } } #endif str[i]=0; } void /* RETURNS: (nothing) */ get_xinput(y,x,str,inmax)/* ARGUMENTS: */ int y,x; /* Row,Col of screen to start */ char *str; /* String buffer to fill in */ int inmax; /* Maximum number of characters */ { /* LOCAL VARIABLES: */ int i=0,cx,cy; /* Position in buffer */ char c; /* Input character */ for(i=0;i0) { i--; cx--; echo(); move(cy,cx); delch(); insch(' '); refresh(); noecho(); } else beep(); } else if (i>=inmax) { beep(); } else { str[i++] = c; cx++; echo(); ADDCH(c); noecho(); } } #else while (1) { alarm(g_max_delay*60); c=getch(); if (c==10 || c==13) break; else if (c==8 || c==16 || c==127) { if (i>0) { i--; printf("%c %c",8,8); refresh(); } else printf("%c",7); } else if (i>=inmax) { printf("%c",7); } else { str[i++] = c; ADDCH(c); } } #endif str[i]=0; } /* void input_pin(y,x,str,inmax) int y,x; char *str; int inmax; { int i=0,cx,cy; char c; if (y && x) move(y,x); cx = x; cy = y; CLRTOEOL(); #ifdef __alpha while (1) { c=getch(); if (c==10 || c==13) break; else if (c==8 || c==16 || c==127) { if (i>0) { i--; cx--; echo(); move(cy,cx); delch(); insch(' '); refresh(); noecho(); } else beep(); } else if (i>=inmax) { beep(); } else { str[i++] = c; cx++; echo(); ADDCH('*'); noecho(); } } #else while (1) { c=getch(); if (c==10 || c==13) break; else if (c==8 || c==16 || c==127) { if (i>0) { i--; printf("%c %c",8,8); refresh(); } else printf("%c",7); } else if (i>=inmax) { printf("%c",7); } else { str[i++] = c; ADDCH('*'); } } #endif str[i]=0; } */ /* ------------------------------------------------------------------------- */ /* PAUSE UNTIL USER HITS A KEY */ /* ------------------------------------------------------------------------- */ void /* RETURNS: (nothing) */ mypause(y,x) /* ARGUMENTS: */ int y,x; /* Row,Col of screen */ { /* LOCAL VARIABLES: */ char c; /* Input character */ mvaddstr(y,x,"Press ENTER/RETURN to continue"); get_input(y,x+30,&c,0); } /* ------------------------------------------------------------------------- */ /* DISPLAY FAREWELL MESSAGE WHEN USER LOGS OUT */ /* ------------------------------------------------------------------------- */ void /* RETURNS: (nothing) */ properly_logout(student_number) /* ARGUMENTS: */ char *student_number; { /* LOCAL VARIABLES: */ FILE *fp; /* Goodbye file pointer */ char buf[255]; /* Input buffer */ char *out_t; char filename[FILE_NAME_LENGTH]; /* DISPLAY EXIT MESSAGE */ CLEAR(); time(&log_out_time); out_t=ctime(&log_out_time); out_t[ strlen(out_t)-1 ]=0; /* Trash newline */ sprintf(filename,"records/duration.db"); if ((fp=fopen(filename,"a"))==NULL) { printf("Error: can't open duration file\n"); return; } flockstream(fp); fprintf(fp,"%s\t%s\t%s\t%s\n",student_number,in_tty,in_t,out_t); funlockstream(fp); fclose(fp); if ((fp=fopen("goodbye.msg","r"))!=NULL) { while (fgets(buf,255,fp)) addstr(buf); fclose(fp); } /* mypause(22,20); */ #ifndef NO_DUP_CHECK logout_check(student_number); #endif #ifndef LOGIN_DBUG sprintf(buf, "This message will last for only %d seconds.",g_delay); mvaddstr(22,20,buf); refresh(); sleep(g_delay); #endif /* CURSES RESTORATION */ resetty(); endwin(); exit(1); } /* ------------------------------------------------------------------------- */ /* Forbid duplicate login */ /* ------------------------------------------------------------------------- */ void /* RETURNS: (nothing) */ dup_login_out() /* ARGUMENTS: */ { /* LOCAL VARIABLES: */ FILE *fp; /* Goodbye file pointer */ char buf[255]; /* Input buffer */ /* DISPLAY EXIT MESSAGE */ CLEAR(); if ((fp=fopen("third-login.msg","r"))!=NULL) { while (fgets(buf,255,fp)) addstr(buf); fclose(fp); } /* mypause(22,20);*/ /* CURSES RESTORATION */ sprintf(buf, "This message will last for only %d seconds.",g_delay); mvaddstr(22,20,buf); refresh(); sleep(g_delay); resetty(); endwin(); exit(1); } void /* RETURNS: (nothing) */ dup_login_warning()/* ARGUMENTS: */ { /* LOCAL VARIABLES: */ FILE *fp; /* Welcome file pointer */ char buf[255]; /* Input buffer */ CLEAR(); if ((fp=fopen("second-login.msg","r"))!=NULL) { while (fgets(buf,255,fp)) addstr(buf); fclose(fp); } mypause(22,20); } /* ------------------------------------------------------------------------- */ /* ALLOW USER TO LOG IN */ /* ------------------------------------------------------------------------- */ char /* RETURNS: Student number */ *login(maxset,section) /* ARGUMENTS: */ int *maxset; /* Set number */ int *section; /* Section number */ { /* LOCAL VARIABLES: */ char *student_number; /* Student number */ int guess, /* User-entered PIN */ login_set; /* Set for which PIN is valid */ int login_section = 0; char buff[20]; /* Input buffer */ T_entry entry; time_t curtime; /* Current time */ int leng; T_student student_data; #define D_S_NUM_Y 11 #define D_S_NUM_X 13 #define D_PIN_Y (D_S_NUM_Y + 2) #define D_PIN_X (D_S_NUM_X + 10) #define D_EXIT_Y (D_S_NUM_Y + 5) #define D_EXIT_X (D_S_NUM_X + 6) #define IN_S_NUM_Y (D_S_NUM_Y) #define IN_S_NUM_X (D_S_NUM_X + 16) #define IN_PIN_Y (D_PIN_Y) #define IN_PIN_X (D_PIN_X + 9) #define M_INVALID_Y (IN_PIN_Y + 1) #define M_INVALID_X (IN_PIN_X) student_number = (char *)malloc( (MAX_STUDENT_NUMBER+4)*sizeof(char)); /* LOOP UNTIL WE ARE LEGALLY LOGGED IN */ do { mvaddstr(D_S_NUM_Y,D_S_NUM_X,"STUDENT NUMBER: "); mvaddstr(D_PIN_Y,D_PIN_X,"CAPA ID: "); mvaddstr(D_EXIT_Y,D_EXIT_X,"To exit system, just hit ENTER/RETURN"); #ifndef NO_PIN /* LOOP UNTIL WE HAVE A STUDENT NUMBER AND PIN */ do { #endif /* NO_PIN */ /* LOOP UNTIL A LEGAL STUDENT NUMBER IS ENTERED */ do { get_input(IN_S_NUM_Y,IN_S_NUM_X,buff, MAX_STUDENT_NUMBER); #ifdef __sun if (!strlen(buff)) kick_out(0); #else if (!strlen(buff)) kick_out(); #endif sscanf(buff,"%s",student_number); leng = strlen(student_number); } while (leng < MAX_STUDENT_NUMBER); #ifndef NO_PIN get_input(IN_PIN_Y,IN_PIN_X,buff,MAX_PIN_CHAR); #ifdef __sun if (!strlen(buff)) kick_out(0); #else if (!strlen(buff)) kick_out(); #endif sscanf(buff,"%d",&guess); } while (guess<1); #endif /* NO_PIN */ student_number[strlen(student_number)] = 0; /* VERIFY PIN */ #ifdef NO_PIN login_set = 1; #else login_set = capa_PIN(student_number,999,guess); #endif /* No_PIN */ #ifdef LOGIN_DBUG fprintf(dfp,"LOGIN:S=%s,Guess=%04d,Actual Pin=%04d,set=%d\n", student_number,guess,capa_PIN(student_number,1, 0), login_set); fprintf(dfp," PIN=%04d,%04d,%04d,%04d,%04d\n", capa_PIN(student_number,1, 0), capa_PIN(student_number,2, 0),capa_PIN(student_number,3, 0), capa_PIN(student_number,4, 0), capa_PIN(student_number,5, 0)); fflush(dfp); #endif if (!login_set) { mvaddstr(M_INVALID_Y,M_INVALID_X, "INVALID LOGIN "); } else { if ( login_set > 99 ) { mvaddstr(M_INVALID_Y,M_INVALID_X, "INCORRECT PIN "); login_set = 0; } if ( capa_get_student(student_number,&student_data) == 0 ) { mvaddstr(M_INVALID_Y,M_INVALID_X,"NO SUCH STUDENT"); login_set=0; } else { login_section = student_data.s_sec; #ifdef LOGIN_DBUG fprintf(dfp, " Student in section %d\n",login_section);fflush(dfp); #endif time(&curtime); if( capa_check_date(CHECK_OPEN_DATE,student_number, login_section,login_set) < 0 ) { mvaddstr(M_INVALID_Y,M_INVALID_X,"NOT YET OPEN!"); login_set=0; } } } } while ( !login_set ); #ifdef LOGIN_DBUG fprintf(dfp, "DEBUG:%s Access granted through set %d section %d\n", student_number, login_set, login_section); fflush(dfp); #endif #ifndef NO_DUP_CHECK switch( login_check(student_number)) { case 0: mvaddstr(M_INVALID_Y,M_INVALID_X,"CANNOT LOGIN"); dup_login_out(); break; case 1: mvaddstr(M_INVALID_Y,M_INVALID_X,"FIRST TIME LOGIN"); break; case 2: mvaddstr(M_INVALID_Y,M_INVALID_X,"SECOND TIME LOGIN"); dup_login_warning( ); break; case -1: #ifdef __sun mvaddstr(M_INVALID_Y,M_INVALID_X,"FILE ERROR"); kick_out(0); #else mvaddstr(M_INVALID_Y,M_INVALID_X,"FILE ERROR"); kick_out(); #endif break; } #endif /* NO_DUP_CHECK */ capa_get_entry(&entry,student_number,login_set); (*maxset) = login_set; (*section) = login_section; capa_mfree(entry.answers); capa_mfree(entry.tries); return (student_number); } /* ------------------------------------------------------------------------- */ /* LOG ANSWERS TO A FILE WITH TIMESTAMP */ /* ------------------------------------------------------------------------- */ int /* RETURNS: error code */ log_attempt(student_number,set,section,log_string) /* ARGUMENTS: */ char student_number[MAX_STUDENT_NUMBER+1]; /* Student number */ int set; /* Set number */ int section; /* Section number */ char *log_string; /* Answer string to log */ { /* LOCAL VARIABLES: */ char filename[FILE_NAME_LENGTH], /* Log filename buffer */ *ct; /* Current time string */ FILE *fp; /* Log file pointer */ time_t t; /* Timestamp for log */ /* OPEN LOG FILE */ sprintf(filename,"records/log%d.db",set); if ((fp=fopen(filename,"a"))==NULL) { printf("Error: can't open log file\n"); return -1; } /* CREATE LOG ENTRY */ time(&t); ct=ctime(&t); ct[ strlen(ct)-1 ]=0; /* Trash newline */ fprintf(fp,"%s %s %s\n",student_number,ct,log_string); fflush(fp); fclose(fp); return 0; } int log_submissions(student_number,set,log_string) char student_number[MAX_STUDENT_NUMBER+1]; int set; char *log_string; { char filename[FILE_NAME_LENGTH], timeStr[FILE_NAME_LENGTH],buf2[MAX_BUFFER_SIZE]; FILE *fp; time_t t; struct tm *tmtime; int do_log_submissions=1,result; char buf[MAX_BUFFER_SIZE]; result=read_capa_config("do_log_submissions",buf); if (result != 0 && result != -1) { if (strcasecmp(buf2,"no")==0) { do_log_submissions=0; } } if (!do_log_submissions) return 0; sprintf(filename,"records/submissions%d.db",set); if ((fp=fopen(filename,"a"))==NULL) { return (-1); } /* CREATE LOG ENTRY */ time(&t); tmtime=localtime(&t); strftime(timeStr,FILE_NAME_LENGTH,"%d/%m %X",tmtime); /*ct[ strlen(ct)-1 ]=0;*/ /* Trash newline */ /*protect_log_string(log_string);*/ fprintf(fp,"%s\t%s\t%s\n",student_number,timeStr,log_string); fflush(fp); fclose(fp); return (0); } #define C_FORWARD 1 #define C_EXIT 2 #define C_MENU 3 #define C_HINT 4 #define C_EXPLAIN 5 #define C_ANSWER 6 #define C_JUMP 7 #define C_DONTCARE 8 #define C_BACKWARD 9 #define C_TIME 10 #define C_NEXTSCR 11 #define C_PREVSCR 12 #define C_SUBJANS 13 /* ------------------------------------------------------------------------- */ /* DISPLAY SUMMARY OF SCORES FOR THE TERM */ /* ------------------------------------------------------------------------- */ void /* RETURNS: (nothing) */ term_summary(student_number,set,section,type) /* ARGUMENTS: */ char *student_number; /* Student Number */ int set; /* Set number */ int *section; /* Section Number */ int type; { /* LOCAL VARIABLES: */ int set_idx, /* Set counter */ i, /* Question counter */ tmp, /* Question correct flag */ set_score, /* Score on a set */ term_score=0, /* Total points received */ term_total=0, /* Total points possible */ result, tot_num_sets=0; T_entry entry; /* Database entry for a set */ char buf[MAX_BUFFER_SIZE], buf2[MAX_BUFFER_SIZE]; T_header header; /* Problem set header */ int topset=1, /* First displayed set */ bottomset, /* Last displayed set */ done=0, /* Done flag */ line, col; int probs_in_set[MAX_BUFFER_SIZE],/* # problem set questions */ start_at[MAX_BUFFER_SIZE], valid_wgt[SMALL_LINE_BUFFER], a_valid_wgt,set_start_line, usr_command,inhibit_response; /* CALCULATE TERM TOTALS */ start_at[0] = -2; probs_in_set[0]= 0; for (set_idx=1; set_idx<=set; set_idx++) { if (capa_get_header(&header,set_idx)) return; if ( capa_check_date(CHECK_OPEN_DATE,student_number,*section,set_idx) < 0 ) continue; tot_num_sets++; capa_get_entry(&entry,student_number,set_idx); sscanf(header.num_questions,"%d", &(probs_in_set[set_idx]) ); start_at[set_idx] = start_at[set_idx-1]+2*(1+probs_in_set[set_idx-1]/50); if ((start_at[set_idx]%12)+2*(1+probs_in_set[set_idx]/50) > 12) start_at[set_idx] = 12*(1+start_at[set_idx]/12); valid_wgt[set_idx] = 0; for (i=0; i='0') && (entry.answers[i]<='9')) term_score += (entry.answers[i] - '0'); } term_total += valid_wgt[set_idx]; capa_mfree(header.weight); capa_mfree(header.partial_credit); capa_mfree(entry.answers); capa_mfree(entry.tries); } /* FIND TOPSET */ line = 12*(start_at[set]/12); /* Top line # of last screen */ for (topset=set; topset>1 && start_at[topset-1]>=line; topset--); /* SHOW HEADER */ CLEAR(); switch(type) { case TERM_SUMMARY: mvaddstr(1,30,"TERM SUMMARY"); break; case EXAM_SUMMARY: mvaddstr(1,30,"EXAM SUMMARY"); break; case QUIZ_SUMMARY: mvaddstr(1,30,"QUIZ SUMMARY"); break; } mvaddstr(3,22," 1 2 3 4 5"); mvaddstr(4,22,"12345678901234567890123456789012345678901234567890"); /* DISPLAY COMMAND MENU */ mvaddstr(21,1,"Enter a command from the list below and press ENTER/RETURN COMMAND:"); mvaddstr(22,1,"M =Go to main menu N =Next Page P =Prev Page"); /* mvaddstr(22,1,"X =eXit M =Go to main menu N =Next Page P =Prev Page"); */ refresh(); /* SHOW TOTALS */ /* if capalogin_show_summary_score is set to none don't show it */ if (term_total > 0 ) { sprintf(buf,"%d sets, total=%3d/%3d (%d%%)", tot_num_sets, term_score, term_total, 100*term_score/term_total); } else { sprintf(buf,"%d sets, total=%3d/%3d", tot_num_sets, term_score, term_total); } result=read_capa_config("capalogin_show_summary_score",buf2); if (result != 0 && result != -1) { if (strcasecmp(buf2,"none")==0) { } else { mvaddstr(19,1,buf); } } else { mvaddstr(19,1,buf); } /* LOOP UNTIL DONE */ while (!done) { /* PRINT 1 LINE SUMMARY PER SET */ line=5; for (set_idx=topset; set_idx<=set; set_idx++) { /* don't show summary for set if inhibit response is set*/ inhibit_response=capa_check_option(OPTION_INHIBIT_RESPONSE,set_idx,*section); if (inhibit_response > 0) continue; if ( capa_check_date(CHECK_OPEN_DATE,student_number,*section,set_idx) < 0 ) continue; set_score=0; set_start_line=line; /* Stop if not enough lines to summarize set */ if (line+2*(probs_in_set[set_idx]/50)>16) break; capa_get_header(&header,set_idx); capa_get_entry(&entry,student_number,set_idx); a_valid_wgt = 0; for (i=0, col=0; i= '0' && entry.answers[i] <= '9' ) { tmp = entry.answers[i] - '0'; } break; } set_score += tmp; col++; if (!((i+1)%50)) { line += 2; col = 0; } } capa_mfree(header.weight); capa_mfree(header.partial_credit); capa_mfree(entry.answers); capa_mfree(entry.tries); move(line, 22+col); CLRTOEOL(); move(line+1, 22+col); CLRTOEOL(); if(a_valid_wgt == 0) { set_score=0; sprintf(buf,"%3d:%3d/%3d(%3d%%) ",set_idx,set_score,a_valid_wgt,set_score); mvaddstr(set_start_line,1,buf); } else { sprintf(buf,"%3d:%3d/%3d(%3d%%) ",set_idx,set_score,a_valid_wgt,100*set_score/a_valid_wgt); mvaddstr(set_start_line,1,buf); } line += 2; } bottomset=set_idx-1; /* Blank out any extra lines */ if (line < 16) { for (set_idx=line; set_idx<=16; set_idx++) { move(set_idx,1); CLRTOEOL(); } } /* PROCESS USER COMMAND */ get_input(21,72,buf,1); if(!strlen(buf)) { usr_command = C_FORWARD; } else { switch(toupper(buf[0])) { /* case 'X': usr_command=C_EXIT; break; */ case 'M': usr_command=C_MENU; break; case 'P': usr_command=C_BACKWARD; break; default : usr_command=C_FORWARD; break; } } switch(usr_command) { case C_DONTCARE: break; case C_FORWARD: /* Forwards */ if (bottomset1 && start_at[topset-1]>=line; topset--); break; case C_MENU: /* Menu */ done=1; break; case C_EXIT: /* Exit */ properly_logout(student_number); break; default: /* Invalid command */ break; } } } void display_hint(char *h) { CLEAR(); wrap(h); mypause(22,20); } #define A_ROW 20 #define S_ROW 21 #define O_ROW 22 #define X_ROW 23 #define A_COL 14 #define S_COL 46 #define H_COL 24 #define E_COL 39 #define X_COL 8 #define R_COL 57 #define U_ANS_CHAR 32 /* ============================================================================= 0001234567890123456789012345678901234567890123456789012345678901234567890123456789 A S1OPTION/ANSWER 12345678901234 ----- *Unanswered O2Options :M = Main Menu :7 = go to #7 :N = Next screen RETURN = Enter/Execute X3 :X = eXit :H = Show Hint :E = Explain RETURN = Next Problem 0123456789012345678901234567890123456789012345678901234567890 ^ ^ ^ ^ ^ ^ X A H E S R */ int show_prior_response(Problem_t *p,int hgr,int prev_ans,int tried,int *allow_h) { char *c_answer_str, tmp_str[MAX_BUFFER_SIZE]; char *response="Incorrect",*answered="Answered"; int can_answer; if( hgr == '0' || p->ans_type==ANSWER_IS_SUBJECTIVE) { switch(prev_ans) { case 'Y': can_answer=NAY; *allow_h=1; c_answer_str = answers_string(ANSWER_STRING_MODE,p); move(A_ROW,A_COL); clrtoeol(); mvaddstr(A_ROW,A_COL,c_answer_str); capa_mfree(c_answer_str); move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"**Correct "); break; case 'y': can_answer=NAY; *allow_h=1; c_answer_str = answers_string(ANSWER_STRING_MODE,p); move(A_ROW,A_COL); clrtoeol(); mvaddstr(A_ROW,A_COL,c_answer_str); capa_mfree(c_answer_str); move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Hand-graded Correct "); break; case '-': can_answer=YAK; move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Unanswered "); break; case 'E': can_answer=NAY; move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Excused "); break; case 'e': can_answer=NAY; move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Excused "); break; case 'n': can_answer=NAY; move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Hand-graded Incorrect "); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': response=answered; case 'N': if ( tried < p->tries ) { can_answer=YAK; if( (p->tries - tried) == 1 ) { sprintf(tmp_str,"*%s, ONE try left!!",response); } else { sprintf(tmp_str,"*%s, tries %2d/%2d ",response,tried,p->tries); } } else { can_answer=NAY; sprintf(tmp_str, "*%s, no more tries",response); } move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,tmp_str); if( (can_answer == YAK) && (p->ans_op == ANS_AND) && (p->ans_cnt > 1)) { sprintf(tmp_str, " Entering answer 1 of %3d ",p->ans_cnt); mvaddstr(A_ROW,S_COL,tmp_str); } break; } } else { /* hand graded question */ can_answer=NAY; move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Hand-graded question "); } /* ------------------------------------------------------------------ */ if (*allow_h && p->hint && ( ( p->show_hint <= tried ) || ( prev_ans == 'y' ) || ( prev_ans == 'Y' ) ) ) { mvaddstr(X_ROW,H_COL,":H = Show Hint"); } else { *allow_h = 0; } if (p->next) mvaddstr(X_ROW,R_COL,"RETURN = Next Problem"); else mvaddstr(X_ROW,R_COL,"RETURN = Main Menu "); return (can_answer); } int show_prior_inhibited_response(Problem_t *p,int hgr,int prev_ans,int tried, int *allow_h) { char tmp_str[MAX_BUFFER_SIZE]; int can_answer; if( hgr == '0' ) { switch(prev_ans) { case '-': can_answer=YAK; move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Unanswered "); break; case 'E': case 'e': case 'n': case 'y': case 'Y': case 'N': if ( tried < p->tries ) { can_answer=YAK; if( (p->tries - tried) == 1 ) { sprintf(tmp_str,"*Answered, ONE try left!! "); } else { sprintf(tmp_str,"*Answered, tries %2d/%2d ",tried,p->tries); } } else { can_answer=NAY; sprintf(tmp_str, "*Answered, no more tries "); } move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,tmp_str); break; } } else { /* hand graded question */ can_answer=NAY; move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Hand-graded question "); } /* ------------------------------------------------------------------ */ if (*allow_h && p->hint && ( p->show_hint <= tried)){ mvaddstr(X_ROW,H_COL,":H = Show Hint"); } else { *allow_h = 0; } if (p->next) mvaddstr(X_ROW,R_COL,"RETURN = Next Problem"); else mvaddstr(X_ROW,R_COL,"RETURN = Main Menu "); return (can_answer); } /* -------------------------------------------- dbug --------------------- */ void print_unit_components(FILE *fp,Unit_t *t) { Unit_E *ue_p; fprintf(fp," Unit::[%s] = %g * ", t->u_symbol, t->u_scale); for(ue_p=t->u_list; ue_p ; ue_p = ue_p->ue_nextp) { fprintf(fp,"(%g*%s^%g) ",ue_p->ue_scale,ue_p->ue_symbol,ue_p->ue_exp); } fprintf(fp,"\n"); fflush(fp); } /*#define ANSWER_STRING_LENG 64*/ #define UNIT_STRING_LENG 64 #define FORMAT_STRING_LENG 32 /* ------------------------------------------------------------------- */ int give_response(Problem_t *p,char **a,int cnt,int *tried,int *log_char) { int can_answer; char tmp_str[MAX_BUFFER_SIZE], *c_answer_str; char *error=NULL; switch( capa_check_answers(p,a,cnt,&error) ) { case EXACT_ANS: move(A_ROW,S_COL); clrtoeol(); mvaddstr(A_ROW,S_COL,"*Yes Computer gets:"); c_answer_str = answers_string(ANSWER_STRING_MODE, p); move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,c_answer_str); capa_mfree((char *)c_answer_str); *log_char='Y'; can_answer=NAY; if( *tried < TRY_BOUND) (*tried)++; break; case APPROX_ANS: move(A_ROW,S_COL); clrtoeol(); mvaddstr(A_ROW,S_COL,"*Yes Computer gets:"); c_answer_str = answers_string(ANSWER_STRING_MODE, p); if(cnt == 1 ) { move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,c_answer_str); } else { /* more than one answer to check ANS_AND */ move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Yes Correct Answers See Above"); move(A_ROW,A_COL); clrtoeol(); mvaddstr(A_ROW,A_COL,c_answer_str); } capa_mfree((char *)c_answer_str); *log_char='Y'; can_answer=NAY; if(*tried < TRY_BOUND) (*tried)++; break; case WANTED_NUMERIC: move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Enter a Number Ans"); *log_char='S'; can_answer=YAK; break; case SIG_FAIL: move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Adjust Sig. Figs. "); *log_char='S'; can_answer=YAK; capa_mfree(error); break; case UNIT_FAIL: move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Units incorrect "); *log_char='U'; can_answer=YAK; capa_mfree(error); break; case UNIT_NOTNEEDED: move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Only a number required"); *log_char='U'; can_answer=YAK; capa_mfree(error); break; case NO_UNIT: move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Units required "); *log_char='u'; can_answer=YAK; break; case BAD_FORMULA:move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Unable to interpret formula"); *log_char='F'; can_answer=YAK; break; case ANS_CNT_NOT_MATCH: move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL,"*Invalid number of answers"); *log_char='C'; can_answer=YAK; break; case INCORRECT: if(*tried < TRY_BOUND) (*tried)++; if ( *tried < p->tries ) { can_answer=YAK; if( (p->tries - *tried) == 1 ) { sprintf(tmp_str,"*Incorrect, ONE try left!!"); } else { sprintf(tmp_str,"*Incorrect, tries %2d/%2d ",*tried,p->tries); } } else { can_answer=NAY; sprintf(tmp_str, "*Incorrect, no more tries"); } move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL, tmp_str); if( (can_answer == YAK) && (p->ans_op == ANS_AND) && (p->ans_cnt > 1) ) { sprintf(tmp_str, " Entering answer 1 of %3d ",p->ans_cnt); mvaddstr(A_ROW,S_COL,tmp_str); } *log_char='N'; break; } return (can_answer); } int give_inhibited_response(Problem_t *p,char **a,int cnt,int *tried,int *log_char) { int can_answer; char tmp_str[MAX_BUFFER_SIZE]; char *error=NULL; switch( capa_check_answers(p,a,cnt,&error) ) { case EXACT_ANS: *log_char='Y'; break; case APPROX_ANS: *log_char='Y'; break; case SIG_FAIL: *log_char='S'; capa_mfree(error); break; case UNIT_FAIL: *log_char='U'; capa_mfree(error); break; case UNIT_NOTNEEDED: *log_char='U'; capa_mfree(error); break; case NO_UNIT: *log_char='u'; break; case BAD_FORMULA:*log_char='F'; break; case INCORRECT: *log_char='N'; break; case WANTED_NUMERIC: *log_char='s'; break; case ANS_CNT_NOT_MATCH: *log_char='C'; break; } if(*tried < TRY_BOUND) (*tried)++; if ( *tried < p->tries ) { can_answer=YAK; if( (p->tries - *tried) == 1 ) { sprintf(tmp_str,"*Answered, ONE try left!! "); } else { sprintf(tmp_str,"*Answered, tries %2d/%2d ",*tried,p->tries); } } else { can_answer=NAY; sprintf(tmp_str, "*Answered, no more tries "); } move(S_ROW,S_COL); clrtoeol(); mvaddstr(S_ROW,S_COL, tmp_str); return (can_answer); } int ask_what_prob(int q_cnt, char *ans) { int not_ok=1,num,anslength,i,j; char buf[5],buf2[MAX_BUFFER_SIZE]; move(14,35); clrtoeol(); move(17,5); clrtoeol(); do { move(14,35); clrtoeol(); move(15,0); clrtoeol(); mvaddstr(15,13,"What problem number:"); move(17,0); clrtoeol(); mvaddstr(17,16," 1 2 3 4 5"); mvaddstr(18,16,"12345678901234567890123456789012345678901234567890"); anslength=strlen(ans); for(i=0;i<=(anslength/50);i++) { if ( g_inhibit_response ) { for(j=50*i;(j<((i+1)*50))&&(j 50 ) { sprintf(buf2,"%3d-%3d",i*50+1,(i+1)*50); mvaddstr(19+i,5,buf2); } } do { get_input(15,34,buf,4); } while(!strlen(buf)); sscanf(buf,"%d",&num); if (num<1 || num>q_cnt) { move(21,5); clrtoeol(); mvaddstr(21,15," Error: Invalid problem number\n"); } else { not_ok = 0; } } while (not_ok); return (num); } /* gather subjective answers from student */ #define BS 8 #define DEL 127 #define ESC 27 #define COLON 58 #define EDIT_HEIGHT 21 #define EDIT_WIDTH 80 #define MENULINE EDIT_HEIGHT void refresh_editor (char **sbuf_pp,int cx,int cy) { int i; CLEAR(); echo(); mvaddstr(MENULINE,0,"Type in the answer, use up, down, left, right keys to move curser"); mvaddstr(MENULINE+1,0,"Enter ctrl-e to exit and submit answer"); mvaddstr(MENULINE+2,0,"Enter ctrl-f to forget answer"); for(i=0;i 0) sbuf_pp[(*cy)-1][abovelen-1]='\0'; if ((abovelen+curlen) < EDIT_WIDTH) { strcat(sbuf_pp[(*cy)-1],sbuf_pp[*cy]); memset(sbuf_pp[(*cy)],'\0',EDIT_WIDTH+1); temp_p=sbuf_pp[*cy]; i=*cy; while(i sy) { sbuf_pp[i]=sbuf_pp[i-1]; move(i,0);CLRTOEOL();mvaddstr(i,0,sbuf_pp[i]); i--; } sbuf_pp[sy+1]=capa_malloc(sizeof(char)*EDIT_WIDTH+1,1); } strcat(sbuf_pp[sy+1],&(sbuf_pp[sy][sx])); memset(&(sbuf_pp[sy][sx]),'\0',EDIT_WIDTH+1-sx); *cx=0; (*cy)++; move(sy,0);CLRTOEOL();mvaddstr(sy,0,sbuf_pp[sy]); move(sy+1,0);CLRTOEOL();mvaddstr(sy+1,0,sbuf_pp[sy+1]); } /* FIXME catch funtion keys and others? */ void handle_esc (unsigned char ca,unsigned char cb,char** sbuf_pp,int *cx,int *cy) { if( ca!='[') return; switch (cb) { case 'A':/* KEY_UP */ if(*cy>0){ (*cy)--; while(*cx>0 && sbuf_pp[*cy][(*cx)-1]=='\0') (*cx)--; /* goto end of line */ } else { beep(); } break; case 'B': /* KEY_DOWN */ if (*cy<(EDIT_HEIGHT-1)) { (*cy)++; while(*cx>0 && sbuf_pp[*cy][(*cx)-1]=='\0') (*cx)--; /* goto end of line */ } else { beep(); } break; case 'C': /* KEY_RIGHT */ if ( *cx<(EDIT_WIDTH-1) && sbuf_pp[*cy][(*cx)]!='\0' ) { (*cx)++; } else { if (*cy<(EDIT_HEIGHT-1)) { (*cy)++; *cx=0; } else { beep(); } } break; case 'D': /* KEY_LEFT */ if(*cx>0) { (*cx)--; } else { if(*cy>0) { (*cy)--; *cx=strlen(sbuf_pp[*cy]); if (*cx==EDIT_WIDTH) (*cx)--; } else { beep(); } } break; default: beep(); return; break; } echo(); move(*cy,*cx); refresh(); noecho(); } void handle_error (unsigned char c,char** sbuf_pp,int cx,int cy) { beep(); } /*FIXME Slower than whale shit*/ void insert_character(unsigned char c,char** sbuf_pp,int *cx,int *cy) { int sx=*cx,sy=*cy; unsigned char temp; while(c!='\0') { if (sx == EDIT_WIDTH) { sx=0;sy++; if (sy == EDIT_HEIGHT) { sy--;sx=EDIT_WIDTH;c='\0';break; } } echo(); ADDCH(c); noecho(); temp=sbuf_pp[sy][sx]; sbuf_pp[sy][sx]=c; c=temp; sx++; } sbuf_pp[sy][sx]=c; (*cx)++; if (*cx == EDIT_WIDTH) { *cx=0;(*cy)++; if (*cy == EDIT_HEIGHT) { (*cy)--;*cx=EDIT_WIDTH-1; } } move(*cy,*cx);refresh(); } int handle_keystrokes_editor(char** sbuf_pp) { int done = 0, forget = 0, cx=0,cy=0; unsigned char c,ca,cb; while (!done) { move(cy,cx);refresh(); c=getch(); switch(c) { case BS: case DEL: remove_character(sbuf_pp,&cx,&cy); break; case CR: case LF: break_line(sbuf_pp,&cx,&cy); break; case ESC: ca=getch();cb=getch(); handle_esc(ca,cb,sbuf_pp,&cx,&cy); break; case 5: /*ctrl-e*/ done=1; break; case 6: /*ctrl-f*/ done=1; forget=1; break; case 12: refresh_editor(sbuf_pp,cx,cy); break; default: if (c < 32 || c>126) { handle_error(c,sbuf_pp,cx,cy); } else { insert_character(c,sbuf_pp,&cx,&cy); } break; } } return forget; } int editor(char*** sbuf_pp) { init_editor(sbuf_pp); return handle_keystrokes_editor(*sbuf_pp); } int answer_subjective(student_number,set,section,prob) char *student_number; int set; int *section; int prob; { int i,length; char date_str[DATE_LENGTH],*tmp; char **sbuf_pp,answer[(EDIT_HEIGHT*(EDIT_WIDTH+1))+1]; char submissions_str[(EDIT_HEIGHT*(EDIT_WIDTH+1))+MAX_BUFFER_SIZE]; time_t curtime; time(&curtime); if( capa_check_date(CHECK_DUE_DATE,student_number,*section,set) > 0 ) { capa_get_date(CHECK_DUE_DATE,student_number,*section,set,date_str); sprintf(answer,"Sorry, the due date was: %s",date_str); move(20,1); clrtobot(); addstr(answer); mypause(23,1); return 0; } if (editor(&sbuf_pp)) { return 0; } answer[0]='\0'; for(i=0;i 0) { strcat(answer,sbuf_pp[i]); length=strlen(answer); answer[length]='\n'; answer[length+1]='\0'; } capa_mfree((char *)sbuf_pp[i]); } capa_set_subjective(set,prob,student_number,answer); tmp=strsave(answer); protect_log_string(tmp); sprintf(submissions_str,"%d\t%s\t",prob,tmp); capa_mfree(tmp); log_submissions(student_number,set,submissions_str); capa_mfree((char *)sbuf_pp); return 1; } void set_entry_tries(int *tried, char *tries, int num, int num_questions) { if((tried[num] >=0) && (tried[num] <= TRY_BOUND) ) { if(tried[num] < 10 ) { tries[3*num] = ' '; tries[3*num+1] = tried[num] + '0'; if(num < num_questions-1) tries[3*num+2] = ','; } else { tries[3*num] = (int)(tried[num]/10) + '0'; tries[3*num+1] = (tried[num] % 10) + '0'; if(num < num_questions-1) tries[3*num+2] = ','; } } else { tries[3*num] = ' '; tries[3*num+1] = 1 + '0'; if(num < num_questions-1) tries[3*num+2] = ','; } } /* -------------------------------------------------------------------------- */ /* LET THE USER ANSWER THE CURRENT PROBLEM SET QUESTIONS */ /* -------------------------------------------------------------------------- */ void try_set(student_number,set,section) char *student_number; int set; int *section; { char a_student_number[MAX_STUDENT_NUMBER+1]; time_t curtime; T_header header; Problem_t *first_problem, *p; T_entry entry; char answer[256], *a_str, **ans_strs; int num, offset, num_questions, start_from, leng; char *log_string,submissions_str[MAX_BUFFER_SIZE],*tmp; int *tried,answered; int scr_idx=1, display=1, second_scr, canAnswer; int usr_command, whereto, allow_hint=0, ex=0; char u_input[64], date_str[DATE_LENGTH], one_line[81]; int log_char, i, j, allow_n, allow_p, allow_subj; strncpy(a_student_number,student_number,MAX_STUDENT_NUMBER+1); time(&curtime); /* Is due date past? */ /* ---------------------------------------- check due date */ #ifndef NO_DATE_CHECK /* ===> if ( compare_datetime(curtime,header.due_date) > 0) { */ if( capa_check_date(CHECK_DUE_DATE,student_number,*section,set) > 0 ) { capa_get_date(CHECK_DUE_DATE,student_number,*section,set,date_str); sprintf(answer," Sorry, the due date was: %s",date_str); move(17,1); clrtoeol(); mvaddstr(17,15,answer); mypause(19,17); return; } #ifdef LOGIN_DBUG fprintf(dfp,"Tryset():(sec=%d,set=%d)[%s]\n",*section,set,date_str); fflush(dfp); #endif /* LOGIN_DBUG */ #endif /* NO_DATE_CHECK */ offset=capa_get_entry(&entry,student_number,set); capa_get_header(&header,set); if (offset<0) offset = -offset; /* newly created entry */ #ifdef LOGIN_DBUG fprintf(dfp,"P set=%d,SN=%s,ANS=%s,TRY=%s\n",set,a_student_number,entry.answers,entry.tries); fflush(dfp); #endif num = capa_parse(set,&first_problem,a_student_number,&num_questions,NULL); #ifdef LOGIN_DBUG fprintf(dfp,"ParseSource:=%d\n",num); fflush(dfp); #endif /* LOGIN_DBUG */ /* DEBUGGING: make sure num_questions is plausible */ if (num_questions>1000 || num_questions<=0) properly_logout(student_number); start_from=ask_what_prob(num_questions,entry.answers); /* initialize log string to all '-' */ tried = (int *)capa_malloc(num_questions+1,sizeof(int)); log_string = (char *)capa_malloc(num_questions+1,sizeof(char)); for (num=0; num 1 ) { num=start_from-1; for (p=first_problem; start_from > 1 && p->next; start_from--) p=p->next; start_from = 0; } if (display) { /* DISPLAY QUESTION */ CLEAR(); second_scr = display_prob_scr(p->question,scr_idx); allow_subj = 0; if( p->ans_type == ANSWER_IS_SUBJECTIVE ) { allow_subj = 1; move(A_ROW,A_COL); clrtoeol(); mvaddstr(A_ROW,A_COL,"Enter :A to answer subjective question"); } mvaddstr(S_ROW,0,"OPTION/ANSWER"); mvaddstr(O_ROW,0,"Options :M = Main Menu :7 = go to # 7"); allow_n = allow_p = 0; if( second_scr && (scr_idx == 1) ) { mvaddstr(O_ROW,E_COL,":N = Next screen"); allow_n=1; } if( second_scr && (scr_idx == 2) ) { mvaddstr(O_ROW,E_COL,":P = Prev screen"); allow_p=1; } mvaddstr(O_ROW,R_COL,"RETURN = Enter/Execute"); if (g_inhibit_response ) { canAnswer = show_prior_inhibited_response(p,header.partial_credit[num],entry.answers[num],tried[num],&allow_hint); } else { canAnswer = show_prior_response(p,header.partial_credit[num],entry.answers[num],tried[num],&allow_hint); } } mvaddstr(X_ROW,X_COL,":X = eXit"); /* <= */ get_xinput(S_ROW,A_COL,u_input,U_ANS_CHAR); display=0; usr_command=C_DONTCARE; /* DEFAULT ACTIONS on empty input */ if(!strlen(u_input)) { usr_command = (p->next? C_FORWARD : C_MENU); } else { if( u_input[0] == ':' ) { switch(toupper( u_input[1] )) { case 'H': if( allow_hint ) { usr_command=C_HINT; } break; case 'M': usr_command=C_MENU; break; case 'N': if( allow_n ) { usr_command=C_NEXTSCR; } break; case 'P': if( allow_p ) { usr_command=C_PREVSCR; } break; case 'X': usr_command=C_EXIT; break; case 'A': if( allow_subj ) { usr_command=C_SUBJANS; } break; default : sscanf(u_input,":%d",&whereto); if(whereto >0 && whereto <= num_questions) usr_command=C_JUMP; break; } } else { /* user entered some answer */ if( p->ans_op == ANS_AND ) { if(canAnswer) { usr_command=C_ANSWER; ans_strs = (char **)capa_malloc(sizeof(char *), p->ans_cnt); ans_strs[0] = (char *)capa_malloc(strlen(u_input)+1,1); strcpy(ans_strs[0],u_input); for(i=1;ians_cnt;i++) { mvaddstr(A_ROW,A_COL," "); mvaddstr(A_ROW,A_COL,ans_strs[i-1]); sprintf(one_line, " Entering answer %3d of %3d ", i+1,p->ans_cnt); mvaddstr(A_ROW,S_COL,one_line); mvaddstr(S_ROW,A_COL," "); get_xinput(S_ROW,A_COL,u_input,U_ANS_CHAR); ans_strs[i] = (char *)capa_malloc(strlen(u_input)+1,1); strcpy(ans_strs[i],u_input); } /* now in ans_strs[][] are user inputs */ } } else { /* one answer or ANS_OR */ ans_strs = (char **)capa_malloc(sizeof(char *), 1); ans_strs[0] = (char *)capa_malloc(strlen(u_input)+1,1); strcpy(ans_strs[0], u_input); if(canAnswer) { usr_command=C_ANSWER; mvaddstr(S_ROW,A_COL," "); mvaddstr(A_ROW,A_COL," "); mvaddstr(A_ROW,A_COL,ans_strs[0]); } } } /* end if u_input[0] == ':' */ } /* end if !strlen(u_input) */ /* PROCESS USER COMMAND */ switch(usr_command) { case C_FORWARD: /* Forwards */ if (p->next) { p=p->next; num++; display=1; allow_hint=0; scr_idx=1; } else mvaddstr(X_ROW,R_COL,"RETURN = Main Menu "); break; case C_NEXTSCR: scr_idx = 2; display=1; break; case C_PREVSCR: scr_idx = 1; display=1; break; case C_EXIT: /* Exit */ ex=1; p=0; break; case C_MENU: /* Return to main menu */ p=0; break; case C_HINT: /* Hint */ if (! p->hint) break; display_hint(p->hint); display=1; break; case C_ANSWER: /* Answer question */ { if(p->ans_type== ANSWER_IS_SUBJECTIVE) { move(A_ROW,A_COL); clrtoeol(); mvaddstr(A_ROW,A_COL,"Enter :A to answer subjective question"); capa_mfree(ans_strs[0]); break; } if( p->ans_op == ANS_AND ) { leng = 0; for(i=0;ians_cnt;i++) { leng += (strlen((char *)ans_strs[i]) + 2); } a_str = (char *)capa_malloc(leng+1,1); a_str[0]=0; strcat(a_str,ans_strs[0]); if ( is_all_ws(ans_strs[0]) ) break; trim_response_ws(ans_strs[0]); for(i=1;ians_cnt;i++) { strcat(a_str,"\t"); strcat(a_str,ans_strs[i]); if ( is_all_ws(ans_strs[i]) ) break; trim_response_ws(ans_strs[i]); } if (i < p->ans_cnt) { display=1; /*handle early breaks out of the*/ break; /*loop which mean typed only ws */ } } else { /* only one answer */ leng = (strlen((char *)ans_strs[0]) + 2); a_str = (char *)capa_malloc(leng+1,1); a_str[0]=0; strcat(a_str,ans_strs[0]); if ( is_all_ws(ans_strs[0]) ) break; trim_response_ws(ans_strs[0]); } tmp=strsave(a_str); protect_log_string(tmp); sprintf(submissions_str,"%d\t%s\t",num+1,tmp); capa_mfree(tmp); log_submissions(student_number,set,submissions_str); { int cnt=((p->ans_op==ANS_AND)?p->ans_cnt:1); if (g_inhibit_response) { canAnswer = give_inhibited_response(p, ans_strs,cnt, &(tried[num]),&log_char); } else { canAnswer = give_response(p, ans_strs,cnt, &(tried[num]),&log_char); } } if( p->ans_op == ANS_AND ) { for(i=0;ians_cnt;i++) { capa_mfree( (char *)ans_strs[i] ); } } else { /* there is only one user answer */ capa_mfree( (char *)ans_strs[0] ); } capa_mfree((char *)ans_strs); capa_mfree( (char *)a_str ); if (p->hint && ( (p->show_hint<=tried[num])|| (log_char == 'y') || (log_char == 'Y') ) ){ allow_hint=1; mvaddstr(X_ROW,H_COL,":H = Show Hint"); } switch(log_char) { case 'U': case 'u': case 'S': case 'F': entry.answers[num]='N'; break; case 'Y': allow_hint=1; mvaddstr(X_ROW,H_COL,":H = Show Hint"); /* fall through here */ default: entry.answers[num]=log_char; break; } log_string[num]=log_char; log_attempt(student_number,set,*section,log_string); /* for (i=0; i if (compare_datetime(curtime,header.due_date) > 0) { */ #ifndef NO_DATE_CHECK if( capa_check_date(CHECK_DUE_DATE,student_number,*section,set) > 0 ) { capa_get_date(CHECK_DUE_DATE,student_number,*section,set,date_str); sprintf(answer,"Sorry, the due date was: %s",date_str); move(20,1); clrtobot(); addstr(answer); mypause(23,1); } else #endif { capa_set_entry(&entry,student_number,set,offset); } } break; case C_JUMP: /* Jump to specific question number */ num=whereto-1; for (p=first_problem; whereto > 1 && p->next; whereto--) p=p->next; display=1; allow_hint=0; scr_idx=1; break; case C_SUBJANS: answered=answer_subjective(student_number,set,section,num+1); if (answered) { tried[num]++; if (p->hint && ((p->show_hint<=tried[num]))) { allow_hint=1; } entry.answers[num]='0'; log_string[num]='A'; log_attempt(student_number,set,*section,log_string); log_string[num]='-'; set_entry_tries(tried,entry.tries,num,num_questions); capa_set_entry(&entry,student_number,set,offset); } display=1; break; case C_DONTCARE: break; } } for (i=0,j=0, num=0; num= '0' && entry.answers[num] <= '9' ) { i = i + (entry.answers[num] - '0'); } if((entry.answers[num]=='E') || (entry.answers[num]=='e')) j = j - (header.weight[num] - '0'); if((tried[num] >=0) && (tried[num] <= TRY_BOUND) ) { if(tried[num] < 10 ) { entry.tries[3*num] = ' '; entry.tries[3*num+1] = tried[num] + '0'; if(num < num_questions-1) entry.tries[3*num+2] = ','; } else { entry.tries[3*num] = (int)(tried[num]/10) + '0'; entry.tries[3*num+1] = (tried[num] % 10) + '0'; if(num < num_questions-1) entry.tries[3*num+2] = ','; } } else { entry.tries[3*num] = ' '; entry.tries[3*num+1] = 1 + '0'; if(num < num_questions-1) entry.tries[3*num+2] = ','; } } capa_mfree(header.weight); capa_mfree(header.partial_credit); sprintf(answer,"Your score for this set is now: %d/%d",i,j); move(20,1); clrtobot(); addstr(answer); mypause(23,1); /* ------- original code , should check due date before save it time(&curtime); if (compare_datetime(curtime,header.due_date) > 0) { if( capa_check_date(CHECK_DUE_DATE,*section,set) > 0 ) { need to deal with due_date sprintf(answer,"Sorry, the due date was: %s",header.due_date); move(20,1); clrtobot(); addstr(answer); mypause(23,1); } else { sprintf(answer,"Your score for this set is now: %d/%d",i,j); move(20,1); clrtobot(); addstr(answer); mypause(23,1); capa_set_entry(&entry,student_number,set,offset); } ------ */ /* FREE UP MALLOC'ED SPACE (VERY IMPORTANT) */ capa_mfree(entry.answers); capa_mfree(entry.tries); free_problems(first_problem); /* log_attempt(student_number,set,*section,log_string); */ capa_mfree(log_string); capa_mfree((char*)tried); if (ex) properly_logout(student_number); } #define COL_ONE 1 #define COL_TWO 17 #define COL_THREE 34 #define COL_FOUR 43 #define COL_FIVE 69 /* ------------------------------------------------------------------------- */ /* REVIEW PREVIOUS PROBLEM SETS */ /* ------------------------------------------------------------------------- */ void /* RETURNS: (nothing) */ view_previous(student_number,set,section) /* ARGUMENTS: */ char *student_number; /* Student number */ int set; /* Set number */ int *section; /* Section number */ { /* LOCAL VARIABLES: */ T_entry entry; /* Database entry */ Problem_t *first_problem, /* Pointer to first problem */ *problem; /* Previous problem */ int num_questions, /* Total # of questions */ ex=0, /* Exit system flag */ display=1, /* Redraw flag */ usr_command, whereto, allow_hint=0, allow_explain=0; int num; /* Temporary variable */ char buf[4], /* Command input buffer */ aLine[MAX_BUFFER_SIZE]; T_header header; /* Set header */ time_t curtime; /* Current time */ double upper_ans; char fmt_ans[ANSWER_STRING_LENG], goto_str[ANSWER_STRING_LENG], tmp_str[ANSWER_STRING_LENG]; int scr_idx=1, second_scr, allow_n, allow_p; /* QUERY USER FOR SET */ move(15,5); /* deleteln(); */ addstr(" Which set would you like to view?"); mvaddstr(16,15, "Enter a set number and press ENTER/RETURN"); move(17,1); clrtoeol(); /* erase Enter a command ... */ do { get_input(15,51,buf,3); } while(!strlen(buf)); sscanf(buf,"%d",&num); if (num<1 || num>set) { move(17,5); clrtoeol(); mvaddstr(17,15," Error: Invalid previous set number\n"); mypause(19,17); return; } /* ------------------------------------ answer date */ time(&curtime); /* ===> if (compare_datetime(curtime,header.answer_date) < 0) { */ if ( capa_check_date(CHECK_ANS_DATE,student_number,*section,num) < 0 ) { move(16,1); clrtoeol(); move(17,5); clrtoeol(); mvaddstr(17,15," Answers are not yet available\n"); mypause(19,17); return; } /* LOAD IN THE INFO NEEDED */ capa_get_header(&header,num); capa_get_entry(&entry,student_number,num); capa_parse(num,&first_problem,student_number,&num_questions,NULL); sprintf(goto_str,"#=go to problem #, [%d problems]", num_questions); for (num=0,problem=first_problem; problem; ) { if (display) { allow_hint = allow_explain=0; allow_n = allow_p = 0; CLEAR(); second_scr = display_prob_scr(problem->question,scr_idx); if( problem->ans_type == ANSWER_IS_FLOAT ) { upper_ans = (double)atof(problem->answer); sprintf(fmt_ans, problem->ans_fmt, upper_ans); } else { sprintf(fmt_ans, "%s", problem->answer); } if( problem->ans_unit ) { sprintf(tmp_str, "Answer: %s %s",fmt_ans,problem->unit_str); } else { sprintf(tmp_str, "Answer: %s",fmt_ans); } mvaddstr(S_ROW,COL_ONE,tmp_str); switch(entry.answers[num]) { case 'Y': mvaddstr(S_ROW,COL_FOUR,"CORRECT "); break; case 'y': mvaddstr(S_ROW,COL_FOUR,"HANDIN CORRECT "); break; case '-': mvaddstr(S_ROW,COL_FOUR,"UNANSWERED "); break; case 'e': mvaddstr(S_ROW,COL_FOUR,"EXCUSED "); break; case 'E': mvaddstr(S_ROW,COL_FOUR,"EXCUSED "); break; case 'n': mvaddstr(S_ROW,COL_FOUR,"HANDIN INCORRECT"); break; case 'N': mvaddstr(S_ROW,COL_FOUR,"INCORRECT "); break; default : if(entry.answers[num] >= '0' && entry.answers[num] <= '9') { sprintf(aLine,"HAND-GRADED %c/%c ",entry.answers[num], header.weight[num]); mvaddstr(S_ROW,COL_FOUR,aLine); } break; } mvaddstr(S_ROW,COL_FIVE,"OPTION:"); mvaddstr(O_ROW,COL_ONE,"M=Main menu"); if( second_scr && scr_idx == 1) { mvaddstr(O_ROW,COL_TWO,"N=Next screen"); allow_n = 1; } if( second_scr && scr_idx == 2) { mvaddstr(O_ROW,COL_TWO,"P=Prev screen"); allow_p = 1; } mvaddstr(O_ROW,COL_THREE,"X=eXit"); mvaddstr(O_ROW,COL_FOUR, "RETURN=Enter/Execute"); if ( problem->hint && ( (problem->show_hint <= problem->tries) || (entry.answers[num] == 'Y') || (entry.answers[num] == 'y') ) ) { allow_hint=1; mvaddstr(O_ROW,COL_FIVE,"H=Hint"); } mvaddstr(X_ROW,COL_ONE,goto_str); if (problem->next) mvaddstr(X_ROW,COL_FOUR,"RETURN=next problem"); else mvaddstr(X_ROW,COL_FOUR,"RETURN=main menu "); if ( problem->explain ) { allow_explain=1; mvaddstr(X_ROW,COL_FIVE,"E=Explain"); } } get_input(S_ROW,COL_FIVE+7,buf,3); display=0; usr_command=C_DONTCARE; /* DEFAULT ACTIONS on empty input */ if(!strlen(buf)) { usr_command = (problem->next? C_FORWARD : C_MENU); } else { switch(toupper(buf[0])) { case 'X': usr_command=C_EXIT; break; case 'M': usr_command=C_MENU; break; case 'H': usr_command=C_HINT; break; case 'E': usr_command=C_EXPLAIN; break; case 'N': if( allow_n ) { usr_command=C_NEXTSCR; } break; case 'P': if( allow_p ) { usr_command=C_PREVSCR; } break; default : sscanf(buf,"%d",&whereto); if(whereto >0 && whereto <= num_questions) usr_command=C_JUMP; break; } } /* PROCESS USER COMMAND */ switch(usr_command) { case C_FORWARD: /* FORWARDS ONE */ if (problem->next) { problem=problem->next; display=1; scr_idx = 1; num++; } else mvaddstr(X_ROW,COL_FOUR,"RETURN=main menu "); break; case C_HINT: /* HINT */ if(allow_hint) { display_hint(problem->hint); display=1; allow_hint = 0; } break; case C_EXPLAIN: /* Explain */ if(allow_explain) { display_hint(problem->explain); display=1; allow_explain=0; } break; case C_NEXTSCR: scr_idx = 2; display=1; break; case C_PREVSCR: scr_idx = 1; display=1; break; case C_EXIT: /* EXIT SYSTEM */ ex=1; problem=0; break; case C_MENU: /* RETURN TO MAIN MENU */ problem=0; break; case C_JUMP: /* JUMP TO SPECIFIC PROBLEM # */ num=whereto-1; for (problem=first_problem; whereto > 1 && problem->next; whereto--) problem=problem->next; display=1; scr_idx = 1; break; case C_TIME: break; case C_DONTCARE: break; } } /* FREE UP MALLOC'ED SPACE - VERY IMPORTANT */ capa_mfree(header.weight); capa_mfree(header.partial_credit); capa_mfree(entry.answers); capa_mfree(entry.tries); free_problems(first_problem); if (ex) properly_logout(student_number); } /* -------------------------------------------------------------------------- */ /* DISPLAY HELP SCREEN */ /* -------------------------------------------------------------------------- */ void /* RETURNS: (nothing) */ display_help() /* ARGUMENTS: (none) */ { /* LOCAL VARIABLES: */ FILE *fp; /* Welcome file pointer */ char buf[255]; /* Input buffer */ CLEAR(); if ((fp=fopen("help.msg","r"))!=NULL) { while (fgets(buf,255,fp)) addstr(buf); fclose(fp); } mypause(22,20); } /* A class directory must have */ /* records/ */ /* */ /* returns: 0 structure is correct, but no set.db files */ /* -1 structure is not correct */ /* >=1 the last set.db */ int check_class_get_set(dir_path) char *dir_path; { char f_name[1024]; int set; if( capa_access(dir_path, F_OK) == 0 ) { /* class dir exists */ sprintf(f_name,"%s/records",dir_path); if( capa_access(f_name, F_OK) == 0 ) { /* class/records dir exists */ for(set = 1; ; set++ ) { sprintf(f_name,"%s/records/set%d.db",dir_path,set); if(capa_access(f_name, F_OK) == -1 ) break; } set--; } else { set = -1; } } else { set = -1; } return (set); } /* -------------------------------------------------------------------------- */ /* Get Exam and Quiz Path */ /* return 0, 1, 2, 3 */ /* -------------------------------------------------------------------------- */ int check_exam_quiz_f() { char buf[MAX_BUFFER_SIZE]; int result = 0, configResult=0; #ifdef LOGIN_DBUG fprintf(dfp,"CHECK EXAM Access() success,and open(),%s\n",buf); fflush(dfp); #endif configResult=read_capa_config("exam_path",buf); if (configResult != 0 && configResult != -1) { Exam_set = check_class_get_set(buf); if(Exam_set > 0 ) { result = 1; sprintf(Exam_path,buf); } } #ifdef LOGIN_DBUG fprintf(dfp,"CHECK EXAM = %d,%s\n", result,Exam_path); fflush(dfp); #endif configResult=read_capa_config("quiz_path",buf); if (configResult != 0 && configResult != -1) { Quiz_set = check_class_get_set(buf); if(Quiz_set > 0 ) { result = (result | 2); sprintf(Quiz_path,buf); } } return (result); } /* -------------------------------------------------------------------------- */ /* DISPLAY MAIN MENU */ /* -------------------------------------------------------------------------- */ void /* RETURNS: (nothing) */ display_menu(student, exam_f, quiz_f) T_student *student; int exam_f, quiz_f; { char buff[MAX_BUFFER_SIZE]; int c_y,configResult,term_summary_button=1; configResult=read_capa_config("term_summary_button",buff); if (configResult != 0 && configResult != -1 ) { if (strcasecmp(buff,"no")==0) { term_summary_button=0; } } CLEAR(); mvaddstr(1,10,student->s_nm); sprintf(buff,"Section: %d",student->s_sec); mvaddstr(1,50,buff); mvaddstr( 4,25," MAIN MENU"); c_y = 6; mvaddstr( c_y,25,"H=Help"); c_y++; if (term_summary_button) { mvaddstr( c_y,25,"S=Summary"); c_y++; } mvaddstr( c_y,25,"T=Try set"); c_y++; mvaddstr( c_y,25,"V=View previous set"); c_y++; if(exam_f) { mvaddstr( c_y,25,"E=view Exam summary"); c_y++; } if(quiz_f) { mvaddstr( c_y,25,"Q=view Quiz summary"); c_y++; } mvaddstr( c_y,25,"X=eXit system"); mvaddstr(14,25,"COMMAND:"); mvaddstr(17, 5,"Enter a command from the list above and press ENTER/RETURN"); } /* -------------------------------------------------------------------------- */ /* CONTROL MAIN MENU SELECTIONS */ /* -------------------------------------------------------------------------- */ void /* RETURNS: (nothing) */ menu_main(student_number,set,section) /* ARGUMENTS: */ char *student_number; /* Student number */ int set; /* Set number */ int section; /* Section number */ { /* LOCAL VARIABLES: */ int ex=0, /* Exit system flag */ cmd; /* User command */ char buff[MAX_BUFFER_SIZE]; /* User command buffer */ T_student a_student; int had_exam, had_quiz, outcome,configResult; #ifdef LOGIN_DBUG fprintf(dfp,"MENU in %s sec=%d\n", student_number,section); fflush(dfp); #endif outcome = check_exam_quiz_f(); had_exam = outcome & 1; had_quiz = outcome & 2; #ifdef LOGIN_DBUG fprintf(dfp,"After check %d\n", outcome); fflush(dfp); #endif capa_get_student(student_number,&a_student); g_inhibit_response=capa_check_option(OPTION_INHIBIT_RESPONSE,set,section); if (g_inhibit_response < 0 ) g_inhibit_response=0; display_menu(&a_student,had_exam, had_quiz); while (!ex) { do { buff[0] = ' '; buff[1] = 0; get_input(14,34,buff,1); cmd=toupper(buff[0]); } while (isspace(cmd)); move(14,35); clrtoeol(); /* PROCESS USER COMMAND */ switch(cmd) { case 'H': /* DISPLAY HELP */ display_help(); display_menu(&a_student,had_exam, had_quiz); break; case 'T': /* TRY CURRENT SET */ try_set(student_number,set,§ion); display_menu(&a_student,had_exam, had_quiz); break; case 'V': /* VIEW PREVIOUS SET */ view_previous(student_number,set,§ion); display_menu(&a_student,had_exam, had_quiz); break; case 'S': /* DISPLAY TERM SUMMARY */ configResult=read_capa_config("term_summary_button",buff); if (configResult != 0 && configResult != -1 ) { if ((strcasecmp(buff,"no")==0)) { break; } } term_summary(student_number,set,§ion,TERM_SUMMARY); display_menu(&a_student,had_exam, had_quiz); break; case 'E': /* VIEW EXAM SUMMARY */ if( had_exam ) { chdir(Exam_path); term_summary(student_number,Exam_set,§ion,EXAM_SUMMARY); display_menu(&a_student,had_exam, had_quiz); chdir(Orig_path); } break; case 'Q': /* VIEW QUIZ SUMMARY */ if( had_quiz ) { chdir(Quiz_path); term_summary(student_number,Quiz_set,§ion,QUIZ_SUMMARY); display_menu(&a_student,had_exam, had_quiz); chdir(Orig_path); } break; case EOF: /* EXIT SYSTEM */ case 'X': ex=1; break; default: /* INVALID COMMAND */ /* printf("Invalid choice\n"); */ break; } } } /* -------------------------------------------------------------------------- */ /* DISPLAY WELCOME MESSAGE WHEN USER LOGS IN */ /* -------------------------------------------------------------------------- */ void /* RETURNS: (nothing) */ welcome() /* ARGUMENTS: */ { /* LOCAL VARIABLES: */ FILE *fp; /* Welcome file pointer */ char buf[TMP_LINE_LENGTH]; /* Input buffer */ CLEAR(); /* sprintf(buf,"This is your %d-time login to this set, good luck!",tries); addstr(buf); */ if ((fp=fopen("welcome.msg","r"))!=NULL) { while (fgets(buf,TMP_LINE_LENGTH-1,fp)) addstr(buf); fclose(fp); } } void print_version() { printf("capalogin\n"); printf(" CAPA version %s, %s\n",CAPA_VER,COMPILE_DATE); printf(" CAPA is released under the GNU GPL v2 see COPYING for details.\n"); } /* ------------------------------------------------------------------------- */ /* DRIVER: INITIALIZE AND GO TO LOGIN */ /* ------------------------------------------------------------------------- */ int main(int argc, char **argv) { /* LOCAL VARIABLES: */ char student_number[MAX_STUDENT_NUMBER+1]; /* Student number */ int set, /* Set number */ section=0, /* Section number */ result; /* stores result from read_capa_config */ char filename[FILE_NAME_LENGTH]; /* Question filename buffer */ #if defined(NeXT) char cwd[FILE_NAME_LENGTH]; #endif char *class_path, buf[MAX_BUFFER_SIZE],*tty; if (argc > 1) { if (strcmp(argv[1],"-v") == 0) {print_version(); exit(0); } } #ifdef LOGIN_DBUG printf("Create login.DBUG file:: argc = %d\n",argc); sprintf(filename,"login.DBUG"); if ((dfp=fopen(filename,"a"))==NULL) { printf("Error: can't open login debug\n"); return; } #endif /* LOGIN_DBUG */ /* GET CURRENT SET NUMBER */ for(set = 1; ; set++ ) { sprintf(filename,"set%d.qz",set); if(capa_access(filename, F_OK) == -1 ) break; } set--; #if defined(NeXT) class_path = getwd(cwd); if( class_path == NULL ) class_path = cwd; #else class_path = getcwd(NULL,512); #endif sprintf(Orig_path,"%s",class_path); free(class_path); /* ---------------------------------------------- CURSES INITIALIZATION */ signal(SIGINT , kick_out); signal(SIGALRM, kick_out); signal(SIGFPE, SIG_IGN); initscr(); savetty(); cbreak(); noecho(); time(&log_in_time); strncpy(in_t,ctime(&log_in_time),31); in_t[ strlen(in_t)-1 ]=0; /* Trash newline */ tty=ttyname(0); if ( tty == NULL ) { strcpy(in_tty,"UNKNOWN"); } else { strcpy(in_tty,tty); } result=read_capa_config("capalogin_goodbye_delay",buf); if (result != 0 && result != -1) { g_delay=atoi(buf); } else { g_delay=5; } result=read_capa_config("capalogin_inactivity_delay",buf); if (result != 0 && result != -1) { g_max_delay=atoi(buf); } else { g_max_delay=60; } welcome(); strcpy(student_number, login(&set,§ion)); student_number[MAX_STUDENT_NUMBER] = 0; #ifdef LOGIN_DBUG fprintf(dfp,"login return:SNum=%s, set=%d, sec=%d\n", student_number,set, section); fflush(dfp); #endif menu_main(student_number,set,section); #ifdef LOGIN_DBUG fclose(dfp); #endif properly_logout(student_number); return 0; }