/* 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 <stdlib.h>
#include <objc/zone.h>
#include <mach/mach.h>
#else
#include <malloc.h>
double atof();
#endif
#include <ctype.h>
#ifdef TRUE
#undef TRUE
#endif
#ifdef FALSE
#undef FALSE
#endif
#include <curses.h>
#if defined(__alpha) || defined(linux)
#ifdef LOGIN_DBUG
#define NO_PIN
#define NO_DATE_CHECK
#define NO_DUP_CHECK
#endif
#include <curses.h>
#else
#if defined(__sun) || defined(hpux) || defined(AIX) || defined(IRIX)
#include <curses.h> /* #include <stdio.h> */
#include <math.h> /* MAXFLOAT */
#else
#include <bsd/curses.h>
#endif
#endif
#include <signal.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <unistd.h>
#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<len; i++) {
getyx(stdscr,y,x);
while (i<len && !isspace(str[i])) i++;
if (x+i-j > 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<len;i++) {
while (i<len && !isspace(str[i])) i++;
if (x+i-j > 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<len;i++) {
if( ( (scr_idx==1) && (lines_cnt < break_pt)) ||
((scr_idx==2) && (lines_cnt > break_pt) && (lines_cnt <= (break_pt+LINES_PER_SCREEN))) ) {
getyx(stdscr,y,x);
/* if (x2>=x) x=x2; else x=x2+80;*/
}
while (i<len && !isspace(str[i])) i++;
onscreen_pr = 0;
#ifdef LOGIN_DBUG
fprintf(dfp,"\n[NewWord line=%d,x=%d,i=%d,j=%d,y=%d]",lines_cnt,x,i,j,y);
#endif
if (x+i-j > 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,"<LineCnt=%d>[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;i<inmax;i++) { move(y,x+i); ADDCH(' '); }
i=0;
if (y && x) move(y,x);refresh();
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
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<probs_in_set[set_idx]; i++) {
valid_wgt[set_idx] += (header.weight[i] - '0');
if((entry.answers[i]=='Y') || (entry.answers[i]=='y'))
term_score += (header.weight[i]-'0');
if((entry.answers[i]=='E') || (entry.answers[i]=='e'))
valid_wgt[set_idx] -= (header.weight[i] - '0');
if((entry.answers[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<probs_in_set[set_idx]; i++) {
tmp=0; a_valid_wgt += (header.weight[i] - '0');
move(line, 22+col); addch(entry.answers[i]);
move(line+1,22+col); addch(header.weight[i]);
switch(entry.answers[i]) {
case 'Y': tmp=header.weight[i] -'0'; break; /* Answer correct */
case 'y': tmp=header.weight[i] -'0'; break; /* Grading correct */
case '-': break; /* Not answered */
case 'N': break; /* Answer incorrect */
case 'n': break; /* Grading incorrect */
case 'e': a_valid_wgt -= (header.weight[i] - '0'); break; /* Excuse */
case 'E': a_valid_wgt -= (header.weight[i] - '0'); break; /* Excuse */
default : if( entry.answers[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 (bottomset<set) { topset=bottomset+1; } else { done=1; }
break;
case C_BACKWARD: /* Backwards */
if (topset<2) break;
line = 12*(start_at[topset-1]/12); /* Top line # of prev screen */
for (; topset>1 && 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<anslength);j++) {
if (ans[j]=='-')
buf2[j-(50*i)]='-';
else
buf2[j-(50*i)]='A';
}
buf2[j-(50*i)]='\0';
} else {
strncpy(buf2,&(ans[50*i]),50);
}
buf2[50]='\0';
mvaddstr(19+i,16,buf2);
if (anslength > 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<EDIT_HEIGHT;i++) { mvaddstr(i,0,sbuf_pp[i]); }
move(cy,cx); refresh(); noecho();
}
void init_editor(char*** sbuf_pp)
{
int ww=EDIT_WIDTH, hh=EDIT_HEIGHT,i;
*sbuf_pp = (char **)capa_malloc(sizeof(char *),hh);
for(i=0;i<hh;i++) {
(*sbuf_pp)[i] = (char *)capa_malloc(sizeof(char)*ww+1,1);
}
CLEAR();echo();
mvaddstr(MENULINE,0,"Type in the answer, use up, down, left, right keys to move cursor");
mvaddstr(MENULINE+1,0,"Enter ctrl-e to exit and submit answer");
mvaddstr(MENULINE+2,0,"Enter ctrl-f to forget answer");
move(0,0); refresh(); noecho();
}
void remove_character(char** sbuf_pp,int *cx,int *cy)
{
int sx=(*cx)-1,sy=*cy;
char temp,*temp_p;
if (*cx==0) {
int abovelen,curlen,diff,i,j;
if (*cy==0) { beep();return;}
abovelen=strlen(sbuf_pp[(*cy-1)]);
curlen=strlen(sbuf_pp[*cy]);
if (abovelen > 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<EDIT_HEIGHT-1) {
sbuf_pp[i]=sbuf_pp[i+1];
echo();move(i,0);CLRTOEOL();mvaddstr(i,0,sbuf_pp[i]);noecho();
i++;
}
sbuf_pp[EDIT_HEIGHT-1]=temp_p;
echo();move(EDIT_HEIGHT-1,0);CLRTOEOL();noecho();
} else {
diff=EDIT_WIDTH-abovelen;
strncat(sbuf_pp[(*cy)-1],sbuf_pp[*cy],diff);
i=diff;j=0;
while(sbuf_pp[*cy][i]!='\0') {
sbuf_pp[*cy][j]=sbuf_pp[*cy][i];
i++;j++;
}
memset(&(sbuf_pp[(*cy)][j]),'\0',EDIT_WIDTH+1-j);
}
echo();move(*cy,0); CLRTOEOL(); mvaddstr(*cy,0,sbuf_pp[*cy]);noecho();
(*cy)--;
echo();move(*cy,0); CLRTOEOL(); mvaddstr(*cy,0,sbuf_pp[*cy]);noecho();
if ( EDIT_WIDTH == ((*cx)=(abovelen-1))) (*cx)--;
if (abovelen==0) *cx=0;
echo();move(*cy,*cx);noecho();
} else {
echo();move(sy,sx);noecho();
temp=sbuf_pp[sy][sx]=sbuf_pp[sy][sx+1];
sx++;
while(temp!='\0') {
echo(); ADDCH(temp); noecho();
temp=sbuf_pp[sy][sx]=sbuf_pp[sy][sx+1];
sx++;
}
echo(); ADDCH(' '); noecho();
(*cx)--;
}
echo();move(*cy,*cx);noecho();
}
void break_line (char** sbuf_pp,int *cx,int *cy)
{
int sx=*cx,sy=*cy,i;
if (sy < EDIT_HEIGHT-1) {
capa_mfree(sbuf_pp[EDIT_HEIGHT-1]);
i=EDIT_HEIGHT-1;
while (i-1 > 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];
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<EDIT_HEIGHT;i++) {
if (strlen(sbuf_pp[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);
sprintf(submissions_str,"%d\t%s\t",prob,answer);
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];
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<num_questions; num++) {
log_string[num]='-';
sscanf(entry.tries + 3*num,"%d,",&(tried[num]) );
}
log_string[num_questions]=0;
capa_set_login_time(student_number,set);
for (num=0,p=first_problem; p; ){
if( start_from > 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;i<p->ans_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;i<p->ans_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;i<p->ans_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]);
}
sprintf(submissions_str,"%d\t%s\t",num+1,a_str);
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;i<p->ans_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<num_questions; i++) { log_string[i] = '-' ; } */
set_entry_tries(tried,entry.tries,num,num_questions);
log_string[num]='-';
/* ------------------------------ check due date */
time(&curtime);
/* ===> 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(20,1); clrtobot(); addstr(answer); mypause(23,1);
} else {
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<num_questions; num++) {
j = j + (header.weight[num] - '0');
if((entry.answers[num]=='Y') || (entry.answers[num]=='y'))
i = i + (header.weight[num] - '0');
if( entry.answers[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;
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>