Back to index

wims  3.65+svn20090927
variables.c
Go to the documentation of this file.
00001 /*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
00002  *
00003  *  This program is free software; you can redistribute it and/or modify
00004  *  it under the terms of the GNU General Public License as published by
00005  *  the Free Software Foundation; either version 2 of the License, or
00006  *  (at your option) any later version.
00007  *
00008  *  This program is distributed in the hope that it will be useful,
00009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  *  GNU General Public License for more details.
00012  *
00013  *  You should have received a copy of the GNU General Public License
00014  *  along with this program; if not, write to the Free Software
00015  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00016  */
00017               /* routines to process variables */
00018 
00019 char *computed_var_start; /* pointer to read-in var def file */
00020 int session_var_ready=0;
00021 char last_host[32]="";
00022 char *robotcheck="";
00023 
00024 char *header_var_name[]={
00025     "REMOTE_ADDR", "HTTP_REFERER", "QUERY_STRING", "HTTP_USER_AGENT",
00026      "HTTP_COOKIE"
00027 };
00028 #define HEADER_VAR_NO (sizeof(header_var_name)/sizeof(header_var_name[0]))
00029 
00030 char *var_allow[]={
00031     "deny" , "init" , "config" ,
00032       "reply", "any", "help"
00033 };
00034 enum {
00035     var_allow_deny, var_allow_init, var_allow_config, 
00036       var_allow_reply, var_allow_any, var_allow_help
00037 } VAR_ALLOWS;
00038 #define VAR_ALLOW_NO (sizeof(var_allow)/sizeof(var_allow[0]))
00039 
00040        /* install a temporary directory for the session */
00041 void mktmpdir(char *p)
00042 {
00043     char *base;
00044     if(p==NULL || *p==0 || strstr(p,"robot")!=NULL) return;
00045     if(strstr(tmp_dir,"sessions")!=NULL) return;
00046     if(ftest("../chroot/tmp/sessions/.chroot")==is_file) base="chroot/tmp";
00047     else base="tmp";
00048     mkfname(tmp_dir,"../%s/sessions/%s",base,p);
00049     remove_tree(tmp_dir); mkdirs(tmp_dir);
00050     chmod(tmp_dir,S_IRUSR|S_IWUSR|S_IXUSR
00051          |S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
00052     setenv("tmp_dir",tmp_dir,1); setenv("TMPDIR",tmp_dir,1);
00053 }
00054 
00055        /* Open session variable file */
00056 FILE *fopen_session_var_file(char read_or_write[])
00057 {
00058     char *nbuf; FILE *f;
00059 
00060     nbuf=mkfname(NULL,"%s/var",session_prefix);
00061     if(read_or_write[0]=='r') {
00062        if(open_working_file(&m_file,nbuf)!=0) return NULL;
00063        mkfname(m_file.name,"session_var");
00064        return stdin;
00065     }
00066     f=fopen(nbuf,read_or_write);
00067     if(f==NULL) {
00068          /* expired_session */
00069        internal_error("fopen_session_var_file(): unable to create session variable file.");
00070     }
00071     mkfname(m_file.name,"session_var");
00072     m_file.l=0;
00073     return f;
00074 }
00075 
00076        /* Open a module file, read only, with name checking. 
00077         * returns NULL if error. */
00078 int read_module_file(char *fname)
00079 {
00080     char nbuf[MAX_FNAME+1];
00081 
00082     if(get_cached_file(fname)>=0) return 0;
00083     if(find_module_file(fname,nbuf,0)) return -1;
00084     if(open_working_file(&m_file,nbuf)!=0) return -1;
00085     untrust|=(untrust>>8);
00086     mystrncpy(m_file.name,fname,sizeof(m_file.name));
00087     if(strncmp(module_prefix,module_dir,strlen(module_dir))!=0) m_file.nocache|=8;
00088     return 0;
00089 }
00090 
00091 int varget[]={ro_module,ro_lang,ro_useropts,ro_worksheet};
00092 #define varget_no (sizeof(varget)/sizeof(varget[0]))
00093 
00094        /* set up ref strings according to protocol */
00095 void set_protocol(void)
00096 {
00097     if(strcmp(protocol,"https")!=0) return;
00098     if(strncmp(ref_name,"http:",5)==0) {
00099        string_modify(ref_name,ref_name+4,ref_name+4,"s");
00100        string_modify(ref_base,ref_base+4,ref_base+4,"s");
00101        force_setvar("wims_ref_name",ref_name);
00102     }
00103 }
00104 
00105        /* verify class participant connection data */
00106 void classlock(void)
00107 {
00108     int lvl;
00109     char *p;
00110     
00111     p=getvar("wims_classlock"); if(p==NULL) lvl=0; else {
00112        p=find_word_start(p);
00113        lvl=*p-'0'; if(lvl<0 || lvl>7) lvl=0;
00114     }
00115     if(lvl==7) {     /* closed */
00116        p=getvar("wims_user");
00117        if(p==NULL || strcmp(p,"supervisor")!=0) user_error("class_closed");
00118     }
00119     if(lvl==2 || lvl==4 || lvl==6) {      /* https */
00120        p=getenv("HTTPS");
00121        if(p==NULL || strcasecmp(p,"on")!=0) user_error("need_https");
00122     }
00123     if(lvl==3 || lvl>=5) {
00124        if(strcmp(last_host,remote_addr)!=0) user_error("bad_host");
00125     }
00126     if((lvl==1 || lvl>=4) && cookiegot[0]==0) {  /* cookie */
00127        setcookie=1;
00128        setvar("cookie_module",getvar(ro_name[ro_module]));
00129        setvar("cookie_cmd",getvar(ro_name[ro_cmd]));
00130        force_setvar(ro_name[ro_module],home_module);
00131        force_setvar(ro_name[ro_cmd],commands[cmd_new]);
00132        setvar("wims_askcookie","yes");
00133        return;
00134     }
00135     else setcookie=0;
00136 }
00137 
00138        /* get static session variables */
00139 void get_static_session_var(void)
00140 {
00141     char *p, *pe, *p2, *p3;
00142     char sbuf[MAX_FNAME+1], tbuf[MAX_LINELEN+1];
00143     mystrncpy(sbuf,session_prefix,sizeof(sbuf));
00144     for(p=sbuf+strlen(sbuf);p>sbuf && *p!='_' && *p!='/'; p--);
00145     if(p>sbuf && *p=='_') *p=0;
00146     accessfile(tbuf,"r","%s/var.stat",sbuf);
00147     p=strrchr(sbuf,'/'); if(p!=NULL) p++; else p=sbuf;
00148     mktmpdir(p);
00149     for(p=find_word_start(tbuf);*p;p=find_word_start(pe)) {
00150        pe=strchr(p,'\n'); if(pe!=NULL) *pe++=0; else pe=p+strlen(p);
00151        p2=strchr(p,'='); if(p2==NULL) continue;
00152        *p2++=0; force_setvar(p,p2);
00153     }
00154     p=getvar("wims_class"); if(p==NULL || *p==0) return;
00155     mkfname(class_dir,"%s/%s",class_base,p);
00156     classlock();
00157     p3=getvar("wims_class_refcolor"); if(p3!=NULL && *p3!=0)
00158       force_setvar("wims_ref_bgcolor",p3);
00159     p2=getvar(ro_name[ro_module]);
00160     if(p2==NULL || strncmp(p2,"classes/",strlen("classes/"))!=0) return;
00161     mkfname(sbuf,"classes/%s",lang);
00162     if(strcmp(sbuf,p2)!=0) force_setvar(ro_name[ro_module],sbuf);
00163 }
00164 
00165        /* set one static session variable */
00166 void set_static_session_var(char *name, char *val)
00167 {
00168     char *p;
00169     char sbuf[MAX_FNAME+1], tbuf[MAX_LINELEN+1];
00170     mystrncpy(sbuf,session_prefix,sizeof(sbuf));
00171     for(p=sbuf+strlen(sbuf);p>sbuf && *p!='_' && *p!='/'; p--);
00172     if(p>sbuf && *p=='_') *p=0;
00173     snprintf(sbuf+strlen(sbuf),sizeof(sbuf)-strlen(sbuf),"/var.stat");
00174     snprintf(tbuf,sizeof(tbuf),"%s=%s",name,val);
00175     setdef(sbuf,tbuf); setvar(name,val);
00176 }
00177 
00178        /* The session is probably robot. */
00179 void robot_doubt(void)
00180 {
00181     char *h, *p;
00182   
00183     p=getvar("special_parm"); h=getvar("module");
00184     if(p==NULL || h==NULL) {
00185        bad: user_error("robot_doubt"); return;
00186     }
00187     p=find_word_start(p); strip_trailing_spaces(p);
00188     if(strcmp(p,"wims")!=0 || strcmp(h,home_module)!=0) goto bad;
00189     set_static_session_var("wims_robotcheck","manual");
00190 }
00191 
00192        /* User has changed module within an operation.
00193         * Probably due to robot access. */
00194 void bad_module(void)
00195 {
00196     char *p;
00197     p=getvar("wims_user"); if(p==NULL) p="";
00198     if(*p==0 && strcmp(robotcheck,"manual")!=0) set_static_session_var("wims_robotcheck","robot");
00199     else setvar("wims_human_access","yes");
00200     user_error("module_change");
00201 }
00202 
00203        /* returns 1 if session directory exists */
00204 int session_exists(char *s)
00205 {
00206     if(ftest(mkfname(NULL,"../%s/%s/var",SESSION_BASE,s))==is_file) return 1;
00207     else return 0;
00208 }
00209 
00210        /* Check the validity of session number .
00211         * returns 0 if OK, else -1. */
00212 int check_session(void)
00213 {
00214     char tbuf[MAX_LINELEN+1], vbuf[MAX_LINELEN+1];
00215     char *p, *pp, *pr;
00216     int i,m,n,pl,rapid,badmod;
00217     struct stat st;
00218 
00219     rapid=badmod=0; pr="";
00220     if(fopen_session_var_file("r")==NULL) return -1;
00221     if(ftest(s2_prefix)!=is_dir) mkdirs(s2_prefix);
00222     session_var_ready=1; memmove(&svar_file,&m_file,sizeof(WORKING_FILE));
00223        /* REMOTE_ADDR */
00224     wgetline(vbuf,MAX_LINELEN,&m_file);
00225     mystrncpy(last_host,vbuf+strlen("REMOTE_ADDR="),sizeof(last_host));
00226     m_file.linepointer++; /* now it points to query_string */
00227     pp=getenv("QUERY_STRING");
00228     if(pp!=NULL && *pp!=0 && strlen(pp)<=MAX_LINELEN) {
00229               /* we compare the query string with the last one. */
00230        char *p1, *p2;
00231        wgetline(tbuf,MAX_LINELEN,&m_file);
00232        p1=tbuf+strlen("QUERY_STRING=");
00233        if(strncmp(tbuf,"QUERY_STRING=",strlen("QUERY_STRING="))==0 && 
00234           strcmp(pp,p1)==0 && strstr(session_prefix,"_test")==NULL) {
00235                      /* query string does not change */
00236            if(ftest(mkfname(NULL,"%s/%s",s2_prefix,lastout))==is_file &&
00237               ftest_size > 0) {
00238               uselast:
00239               putlastout(); delete_pid(); exit(0);
00240            }
00241            else {
00242               if(cmd_type==cmd_new || cmd_type==cmd_renew ||
00243                  cmd_type==cmd_reply || cmd_type==cmd_next) {
00244                   cmd_type=cmd_resume;
00245                   force_setvar(ro_name[ro_cmd],"resume");
00246                   forceresume=1;              
00247               }
00248            }
00249        }
00250               /* stop rapidfire requests */
00251        if((cmd_type==cmd_new || cmd_type==cmd_renew) &&
00252           strncmp(p1,"session=",strlen("session="))==0 &&
00253           strncmp(pp,"session=",strlen("session="))==0) {
00254            p1=strchr(p1,'&'); if(p1==NULL) p1="";
00255            p2=strchr(pp,'&'); if(p2==NULL) p2=""; pr=p2;
00256            if(strcmp(p1,p2)==0) rapid=1;
00257        }
00258     }
00259     m_file.linepointer=3;
00260     wgetline(vbuf,MAX_LINELEN,&m_file); /* stored user_agent */
00261 /*    p=getenv("HTTP_USER_AGENT"); if(p==NULL) p="";
00262     if(strcmp(vbuf+strlen("HTTP_USER_AGENT="),p)!=0) bad_ident(); */
00263     m_file.linepointer=HEADER_VAR_NO;
00264     pl=strlen(var_prefix);i=-1;
00265     while(wgetline(tbuf,MAX_LINELEN,&m_file)!=EOF) {
00266        if(tbuf[0]==0) break;       /* blank line */
00267        if(strncmp(tbuf,var_prefix,pl)!=0) break;
00268        i++;if(i>=RO_NAME_NO) break;
00269        for(n=0;n<varget_no && varget[n]!=i;n++);
00270        if(n>=varget_no) continue;
00271        m=pl+strlen(ro_name[i]);
00272        if(tbuf[m]!='=' || tbuf[m+1]==0) continue;
00273        if(i==ro_module && cmd_type!=cmd_new && cmd_type!=cmd_intro) {
00274            char *pp;
00275            pp=getvar(ro_name[i]);
00276            if(pp!=NULL && *pp!=0 && strcmp(pp,tbuf+m+1)!=0) badmod=1;
00277        }
00278        if(i==ro_lang && !user_lang)
00279          force_setvar(ro_name[i],tbuf+m+1);
00280        else setvar(ro_name[i],tbuf+m+1);
00281     }
00282        /* recover internal variables */
00283     do {
00284        char *v;
00285        if(tbuf[0]==0) break;
00286        v=strchr(tbuf,'=');
00287        if(v==NULL) break; else *(v++)=0;
00288        if(strncmp(tbuf,var_prefix,strlen(var_prefix))!=0) setenv(tbuf,v,1);
00289        else if(tbuf[strlen(var_prefix)]) force_setvar(tbuf+strlen(var_prefix),v);
00290     }
00291     while(wgetline(tbuf,MAX_LINELEN,&m_file)!=EOF);
00292     get_static_session_var();
00293     robotcheck=getvar("wims_robotcheck"); if(robotcheck==NULL) robotcheck="";
00294        /* form access means manual access. Mark this. */
00295     if(form_access && strcmp(robotcheck,"manual")!=0) {
00296        robotcheck="manual";
00297        set_static_session_var("wims_robotcheck","manual");
00298     }
00299     else if(strcmp(robotcheck,"robot")==0) robot_doubt();
00300     if(badmod) bad_module();
00301     if(cookiegot[0]!=0) {
00302        p=getvar("wims_sescookie");
00303        if(p!=NULL && *p!=0 && strcmp(cookiegot,p)!=0) bad_ident();
00304     }
00305     p=getvar("wims_sreferer");
00306     if(p!=NULL && *p!=0) {
00307        setenv("HTTP_REFERER",p,1); setvar("httpd_HTTP_REFERER",p);
00308     }
00309     if(rapid) {
00310        int rapidfiredelay;
00311        char *pw, fnbuf[MAX_FNAME+1];
00312               /* Delay: 10 seconds within worksheets, 1 second otherwise. */
00313        pw=getvar("wims_developer");
00314        if(pw!=NULL && *pw!=0) goto delcheckend;
00315        pw=getvar("wims_user"); 
00316        if(pw==NULL || *pw==0 || strcmp(pw,"supervisor")==0) rapidfiredelay=1;
00317        else {
00318            pw=strstr(pr,"&+worksheet=");
00319            if(pw!=NULL && myisdigit(*(pw+strlen("&+worksheet=")))) rapidfiredelay=10;
00320            else rapidfiredelay=2;
00321        }
00322        if(ftest(mkfname(fnbuf,"%s/%s",s2_prefix,lastout))==is_file
00323           && ftest_size > 0
00324           && stat(fnbuf,&st) == 0
00325           && st.st_mtime > nowtime-rapidfiredelay && st.st_mtime <= nowtime)
00326          goto uselast;
00327     }
00328        /* set protocol string */
00329     delcheckend: pp=getvar("wims_protocol");
00330     if(pp!=NULL && strcmp(pp,"https")==0) {
00331        protocol="https"; set_protocol();
00332     }
00333     useropts(); return 0;
00334 }
00335        /* check whether a session is trapped. */
00336 void trap_check(char *s)
00337 {
00338     char buf[64];
00339     char *p;
00340     time_t t1;
00341 
00342     setvar("wims_session_expired",s);
00343     accessfile(tmplbuf,"r","../tmp/log/trap.check");
00344     if(tmplbuf[0]==0) return;
00345     p=getenv("REMOTE_ADDR");if(p==NULL) return;
00346     snprintf(buf,sizeof(buf),":%s,%s,",s,p);
00347     p=strstr(tmplbuf,buf); if(p==NULL) return;
00348     p+=strlen(buf);*find_word_end(p)=0;
00349     t1=atoi(p);
00350     if(t1>nowtime) user_error("trapped");
00351 }
00352 
00353 char cars[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
00354 
00355 void set_cookie(void)
00356 {
00357     #define keylen 20
00358     char sesbuf[16], keybuf[keylen+8];
00359     char *p;
00360 
00361     p=getvar(ro_name[ro_session]); if(p==NULL) return;
00362     mystrncpy(sesbuf,p,sizeof(sesbuf));
00363     if(strchr(sesbuf,'_')==NULL) { /* main session */
00364        int i;
00365        for(i=0;i<keylen;i++) keybuf[i]=cars[random()%36];
00366        keybuf[keylen]=0; cookiegot[0]=0;
00367        snprintf(cookieset,sizeof(cookieset),"%s-%s",sesbuf,keybuf);
00368        set_static_session_var("wims_sescookie",cookieset);
00369        setcookie=1;
00370     }
00371     else {    /* subsession */
00372        p=getvar("wims_sescookie"); if(p && *p)
00373          mystrncpy(cookieset,p,sizeof(cookieset));
00374     }
00375 }
00376 
00377        /* create a session number */
00378 void create_session(void)
00379 {
00380     long t; char session_str[64],*s;
00381     char *p, ses_dir_buf[MAX_FNAME+1], sesrandbuf[MAX_LINELEN+1];
00382     int i;
00383     
00384        /* no session is created for robots */
00385     if(robot_access) return;
00386     sesrandbuf[0]=0;
00387        /* If session is given in request_string: use it. */
00388     s=getvar(ro_name[ro_session]); if(s==NULL) goto creat;
00389     mystrncpy(session_str,s,sizeof(session_str));
00390     s=strchr(session_str,'.'); if(s!=NULL) *s=0;
00391     s=session_str;
00392     if(*s!=0) {
00393        int i;
00394        mkfname(ses_dir_buf,"%s/%s",session_dir,s);
00395        i=ftest(ses_dir_buf);
00396        if(i<0) {
00397            trap_check(s);
00398               /* subsession */
00399            if(strlen(s)>10 && strchr(s,'_')!=NULL) {
00400               char *tt;
00401               tt=strrchr(ses_dir_buf,'_'); if(tt!=NULL) *tt=0;
00402               /* parent session gone. */
00403               if(ftest(ses_dir_buf)<0) goto creat;
00404               goto creat2;
00405            }
00406            else goto creat;
00407        }
00408        if(i!=is_dir) {
00409            trap_check(s);
00410            remove_tree(ses_dir_buf); goto creat;
00411        }
00412        return;
00413     }
00414     creat:
00415     t=create_job_ident();
00416     for(i=0;i<MAX_SESRANDOM;i++)
00417       snprintf(sesrandbuf+strlen(sesrandbuf),
00418               sizeof(sesrandbuf)-strlen(sesrandbuf),
00419               "%d,",sesrandomtab[i]);
00420     sesrandbuf[strlen(sesrandbuf)-1]='\n';
00421     snprintf(session_str,sizeof(session_str),"%c%c%08lX",
00422             cars[random()%36],cars[random()%36],t);
00423     creat2:
00424     force_setvar(ro_name[ro_session],session_str);
00425     setsesdir(session_str);
00426        /* check whether the environment is created. */
00427     s=getvar(ro_name[ro_session]);
00428     if(s==NULL || strcmp(s,session_str))
00429       internal_error("cannot_create_session_number");
00430     snprintf(ses_dir_buf,sizeof(ses_dir_buf)-100,"%s/%s",
00431             session_dir,session_str);
00432     if(mkdir(ses_dir_buf,S_IRWXU)==-1)
00433       internal_error("cannot_create_session_directory");
00434     mkfname(s2_prefix,"%s/%s",s2_dir,session_str);
00435     if(mkdir(s2_prefix,S_IRWXU)==-1) mkdirs(s2_prefix);
00436     mystrncpy(session_prefix,ses_dir_buf,sizeof(session_prefix)); create_pid();
00437     if(strchr(session_str,'_')==NULL) {
00438        if((s=getenv("HTTP_REFERER"))!=NULL && *s!=0 && strlen(s)<MAX_FNAME-20
00439           && strstr(s,"wims")==NULL) {
00440            char *tt;
00441            tt=getenv("SERVER_NAME");
00442            if(tt==NULL || *tt==0 || strstr(s,tt)==NULL)
00443              set_static_session_var("wims_sreferer",s);
00444        }
00445        if(sesrandbuf[0]) set_static_session_var("wims_sesrandom",sesrandbuf);
00446     }
00447        /* determine http protocol name. How to detect? */
00448     p=getenv("HTTPS"); if(p!=NULL && strcmp(p,"on")==0) {
00449       protocol="https"; set_protocol();
00450     }
00451     force_setvar("wims_protocol",protocol);
00452     new_session=1; session_serial=0;
00453     setvar("wims_new_session","yes");
00454     if(strchr(session_str,'_')!=NULL) get_static_session_var();
00455     set_cookie();
00456 }
00457 
00458        /* Register time of the request. */
00459 void set_req_time(void)
00460 {
00461     char tstr[64];
00462     
00463     snprintf(tstr,sizeof(tstr),"%04d-%02d-%02d.%02d:%02d:%02d=%lu",
00464            (now->tm_year)+1900, (now->tm_mon)+1, now->tm_mday,
00465            now->tm_hour, now->tm_min, now->tm_sec, nowtime);
00466     force_setvar("wims_req_time",tstr);
00467     if(cmd_type == cmd_new || cmd_type == cmd_renew)
00468       force_setvar("wims_module_start_time",tstr);
00469     if(new_session) force_setvar("wims_session_start_time",tstr);
00470 }
00471 
00472        /* set up module_prefix. */
00473 void set_module_prefix(void)
00474 {
00475     char tbuf[MAX_FNAME+1], mmbuf[MAX_FNAME+1], *p, *pp, *ps;
00476     int t,ft;
00477     struct stat st;
00478 
00479     isclassmodule=0;
00480     p=getvar(ro_name[ro_module]);
00481     if(p==NULL || *p==0) user_error("no_module_name");
00482        /* security measure: we should not allow users to go back to
00483         * parent directories. */
00484     if(strstr(p,parent_dir_string)!=NULL) user_error("wrong_module");
00485     if(strncmp(p,"classes/",strlen("classes/"))==0) isclassmodule=1;
00486     if(strncmp(p,"devel/",strlen("devel/"))==0) isdevelmodule=1;
00487     mkfname(module_prefix,"%s/%s",module_dir,p);
00488        /* Now no symbolic link should appear in the module path. */
00489     mkfname(tbuf,"modules/%s",p);
00490     for(t=0,ps=pp=strchr(tbuf+strlen("modules/"),'/'); pp;
00491        *pp='/', ps=pp, pp=strchr(pp+1,'/'), t++) {
00492        *pp=0; if(lstat(tbuf,&st)) user_error("wrong_module");
00493        if(t>0 && S_ISLNK(st.st_mode)) {
00494            if(strcmp(ps,"/local")!=0 ||
00495               strncmp(tbuf,"modules/home",strlen("modules/home"))==0)
00496              user_error("wrong_module");
00497        }
00498     }
00499        /* Check validity of the module. */
00500     mkfname(tbuf,"%s/%s",module_prefix,html_file);
00501     ft=stat(tbuf,&st);
00502     if(ft!=0 && p[strlen(p)-3]!='.') {
00503        int i,j;
00504        char *l;
00505        l=getvar(ro_name[ro_lang]);
00506        j=available_lang_no;
00507        for(i=-1;i<j && ft!=0;i++) {
00508            if(i<0) mkfname(mmbuf,"%s.%s",p,l);
00509            else mkfname(mmbuf,"%s.%s",p,available_lang[i]);
00510            mkfname(module_prefix,"%s/%s",module_dir,mmbuf);
00511            mkfname(tbuf,"%s/%s",module_prefix,html_file);
00512            ft=stat(tbuf,&st);
00513        }
00514        if(ft==0) force_setvar(ro_name[ro_module],mmbuf);
00515     }
00516     if(ft!=0 && !isclassmodule) user_error("wrong_module");
00517     setenv("module_dir",module_prefix,1); setvar("module_dir",module_prefix);
00518     module_index();
00519 }
00520 
00521        /* set up session_prefix. */
00522 int set_session_prefix(void)
00523 {
00524     char *p, s[32];
00525 
00526     if(robot_access) {
00527        mystrncpy(session_prefix,robot_session,sizeof(session_prefix));
00528        mystrncpy(s2_prefix,robot_session,sizeof(session_prefix));
00529        return 0;
00530     }
00531     p=getvar(ro_name[ro_session]);
00532     if(p==NULL || *p==0) user_error("no_session");
00533        /* same reason as for modules */
00534     if (strchr(p,'/')!=NULL || strstr(p,parent_dir_string)!=NULL
00535        || *find_word_end(p)!=0) user_error("wrong_session");
00536     mystrncpy(s,p,sizeof(s));
00537     p=strchr(s,'.'); if(p!=NULL) *p=0;
00538     mkfname(session_prefix,"%s/%s",session_dir,s);
00539     p=strstr(session_prefix,"_mhelp"); if(p!=NULL) *p=0;
00540     if(ftest(session_prefix)!=is_dir) return -1;
00541     mkfname(s2_prefix,"%s/%s",s2_dir,s);
00542     setenv("session_dir",session_prefix,1);
00543     setenv("s2_dir",s2_prefix,1);
00544     if(ftest(mkfname(NULL,"%s/.trap",s2_prefix))==is_file)
00545       user_error("trapped");
00546     return 0;
00547 }
00548 
00549        /* check reserved name values in query_string */ 
00550 void parse_ro_names(void)
00551 {
00552     int i;
00553     char *cmd, *p;
00554     char sesbuf[64];
00555     create:
00556     cmd=getvar(ro_name[ro_cmd]);
00557     if(cmd==NULL || *cmd==0) user_error("no_command");
00558     for(i=0;i<CMD_NO;i++) if(strcmp(cmd,commands[i])==0) break;
00559     if(i>=CMD_NO) user_error("bad_command");
00560     cmd_type=i;
00561     if(cmd_type == cmd_new) {
00562        create_session();
00563        if(set_session_prefix()==0) {
00564            check_session();
00565            set_module_prefix();
00566        }
00567        else goto redo;
00568     }
00569     if (set_session_prefix()==-1 || (cmd_type != cmd_new && check_session())) {
00570        redo:
00571        force_setvar(ro_name[ro_cmd],commands[cmd_new]);
00572        if(strcmp(ro_name[ro_module],home_module)!=0) user_var_no=0;
00573        goto create;
00574     }
00575     if(!new_session) create_pid();
00576     session_serial++;
00577     if(robot_access) session_serial=1;
00578     snprintf(sesbuf,sizeof(sesbuf),"%d",session_serial);
00579     force_setvar("wims_session_serial",sesbuf);
00580     p=getvar(ro_name[ro_session]);
00581     if(p==NULL || *p==0) internal_error("parse_ro_names(): bad session.\n");
00582     mystrncpy(sesbuf,p,sizeof(sesbuf));
00583     p=strchr(sesbuf+5,'.'); if(p!=NULL) *p=0;
00584     mktmpdir(sesbuf);
00585     if(!robot_access) {
00586        setsesdir(sesbuf);
00587        p=strchr(sesbuf,'_');
00588        if(p!=NULL) force_setvar("wims_subsession",p);
00589     }
00590     snprintf(sesbuf+strlen(sesbuf),sizeof(sesbuf)-strlen(sesbuf),
00591             ".%d",session_serial);
00592     force_setvar(ro_name[ro_session],sesbuf);
00593     if(cmd_type != cmd_new) set_module_prefix();
00594     set_req_time();
00595     if(robot_access) check_load(0);
00596     else {
00597        if(new_session) auth();
00598        else {
00599            p=getvar("wims_user"); if(p==NULL || *p==0) check_load(2);
00600        }
00601     }
00602     if(cmd_type==cmd_help && open_working_file(&m_file,module_about_file)==0)
00603       var_proc(NULL,0);
00604 }
00605 
00606 
00607        /* returns positive or 0 if var_def found, otherwise returns -1. */
00608 int var_def_check(char *name)
00609 {
00610     char *p, nbuf[MAX_NAMELEN+1];
00611     int i,tt;
00612     
00613     tt=-1;
00614     for(p=name+strlen(name);p>name && myisdigit(*(p-1));p--);
00615     if(*p && *p!='0' && p>name) tt=atoi(p);
00616     else p=name+strlen(name);
00617     if(p>name+MAX_NAMELEN) p=name+MAX_NAMELEN;
00618     memmove(nbuf,name,p-name); nbuf[p-name]=0;
00619     i=search_list(var_def,defined_var_total,sizeof(var_def[0]),nbuf);
00620     if(i<0) return -1;
00621     while(i>0 && tt<var_def[i].beg && strcmp(nbuf,var_def[i-1].name)==0) i--;
00622     while(i<defined_var_total-1 && tt>var_def[i].end &&
00623              strcmp(nbuf,var_def[i+1].name)==0) i++;
00624     if(tt<var_def[i].beg || tt>var_def[i].end) return -1;
00625     return i;
00626 }
00627 
00628 int var_def_name(char *n, int v)
00629 {
00630     char *q, *r;
00631     int j;
00632     if(strlen(n)>=MAX_NAMELEN) module_error("defn_too_long");
00633     var_def[v].name=n;
00634     if((strncmp(n,wims_prefix,wpflen)==0 && 
00635        (strncmp(n,"wims_priv_",strlen("wims_priv_"))==0 ||
00636         search_list(internal_name,INTERNAL_NAME_NO,
00637                    sizeof(internal_name[0]),n+wpflen)>=0)) ||
00638        search_list(ro_name,RO_NAME_NO,sizeof(ro_name[0]),n)>=0) {
00639        setvar("wims_reserved_name",n);
00640        module_error("name_is_reserved");
00641     }
00642     for(q=n;myisalnum(*q) || *q=='_'; q++);
00643     if(q==n) {
00644        illegal: setvar("wims_bad_name",n);
00645        module_error("illegal_name");
00646     }
00647     if(*q=='[') {
00648        *q++=0; r=find_matching(q,']');
00649        if(r==NULL) goto illegal;
00650        *r=0; j=atoi(q);
00651        if(j<1) j=1; if(j>MAX_VAR_NUM) j=MAX_VAR_NUM;
00652        var_def[v].beg=1; var_def[v].end=j;
00653        return j;
00654     }
00655     if(*q) goto illegal;
00656     for(r=q; r>n && myisdigit(*(r-1)); r--);
00657     if(*r && *r!='0' && r>n) {
00658        var_def[v].beg=var_def[v].end=atoi(r); *r=0;
00659     }
00660     else var_def[v].beg=var_def[v].end=-1;
00661     return 1;
00662 }
00663 
00664 int var_def_allow(char *p, int v)
00665 {
00666     int i;
00667     for(i=0;i<VAR_ALLOW_NO && strcasecmp(p,var_allow[i])!=0; i++);
00668     if(i>=VAR_ALLOW_NO) module_error("bad_allow");
00669     else var_def[v].allow=i;
00670     return i;
00671 }
00672 
00673 int varsort(const void *p1, const void *p2)
00674 {
00675     int i; const struct VAR_DEF *pp1, *pp2;
00676     pp1=p1; pp2=p2; i=strcmp(pp1->name,pp2->name);
00677     if(i) return i; else return pp1->end - pp2->end;
00678 }
00679 
00680        /* parse module's variable definitions */
00681 void get_var_defs(void)
00682 {
00683     int i, j, k, v, add;
00684     char *p, *p1, *wlist[MAX_VAR_NUM];
00685     
00686     defined_var_total=0;
00687     if(read_module_file(var_def_file)!=0) return;
00688     var_def_buf=m_file.textbuf;
00689     for(m_file.l=v=add=0;v<MAX_VAR_NUM && m_file.l<m_file.linecnt;m_file.l++) {
00690        if(m_file.lines[m_file.l].isstart!=1) continue;
00691        p=find_word_start(m_file.lines[m_file.l].address);
00692        if(*p==0 || *p==comment_prefix_char) continue;  /* empty or comment lines */
00693        items2words(p);
00694        if((p1=strchr(p,':'))!=NULL) {     /* new format */
00695            *p1=' '; i=cutwords(p,wlist,MAX_VAR_NUM); if(i<=1) continue;
00696            k=var_def_allow(wlist[0],v);
00697            for(j=1;j<i && v<MAX_VAR_NUM;j++) {
00698               add+=var_def_name(wlist[j],v); var_def[v].allow=k;
00699               v++;
00700            }
00701        }
00702        else {
00703            i=cutwords(p,wlist,3); if(i<2) module_error("too_few_columns");
00704            add+=var_def_name(wlist[0],v); var_def_allow(wlist[1],v);
00705            var_def[v].defined_in_parm=0;
00706            v++;
00707        }
00708     }
00709     if(v>=MAX_VAR_NUM) module_error("too_many_variables");
00710     defined_var_total=v;
00711     qsort(var_def,v,sizeof(var_def[0]),varsort);
00712     p=getvar(ro_name[ro_module]);
00713     if(p==NULL || strncmp(p,"devel/",6)!=0) return;
00714     for(v=1;v<defined_var_total;v++) {
00715        if(strcmp(var_def[v].name,var_def[v-1].name)==0 &&
00716           var_def[v].beg<=var_def[v-1].end) {
00717            setvar("wims_bad_name",var_def[v].name);
00718            module_error("multiple_declaration");
00719        }
00720     }
00721 }
00722 
00723        /* returns 1 if hacked, else 0. */
00724 int try_hack(char *var)
00725 {
00726     int i, al;
00727     char vbuf[16];
00728     i=var_def_check(var);
00729     if(i<0) return 0;
00730     al=var_def[i].allow;
00731     if(al != var_allow_any) switch(cmd_type) {
00732        case cmd_new:
00733        case cmd_renew:      {
00734            if (al != var_allow_init && al != var_allow_config) return 0;
00735            else break;
00736        }
00737        case cmd_config: {
00738            if(al != var_allow_config) return 0;
00739            else break;
00740        }
00741        case cmd_reply:      {
00742            if(al != var_allow_reply) return 0;
00743            else break;
00744        }
00745        case cmd_help: {
00746            if(al != var_allow_help) return 0;
00747            else break;
00748        }
00749        default: return 0;
00750     }
00751     snprintf(vbuf,sizeof(vbuf),"%d",(int) irand(21));
00752     var_hacking=1; setvar(var,vbuf); var_hacking=0;
00753     return 1;    
00754 }
00755     
00756        /* set environ variables from last session save
00757         * The session var file starts with variables which should not
00758         * be restored. Variables which are restored follow a blank line. */
00759 void set_vars_from_session(void)
00760 {
00761     char lbuf[MAX_LINELEN+1];
00762     int i;
00763     char *p;
00764 
00765     if(session_var_ready) memmove(&m_file,&svar_file,sizeof(WORKING_FILE));
00766     else fopen_session_var_file("r");
00767        /* look for the first blank line. */
00768     for(i=0;i<m_file.linecnt && (m_file.lines[i].isstart==0 || m_file.lines[i].llen>0);i++);
00769     for(i++;i<m_file.linecnt && m_file.lines[i].llen==0;i++);
00770     if(i>=m_file.linecnt) return;
00771     m_file.linepointer=i;
00772     if(isdevelmodule && strstr(session_prefix,"_test")==NULL) isdevelmodule=0;
00773     while(wgetline(lbuf,MAX_LINELEN, &m_file)!=EOF) {
00774        p=strchr(lbuf,'='); 
00775        if(p==NULL || p<=lbuf || isspace(lbuf[0]) ) {
00776                      /* this time it is corrupted var file */
00777          call_ssh("cat %s/var >%s/corrupt.var.bak",session_prefix,log_dir);
00778          internal_error("get_vars_from_session(): corrupt session variable file.");
00779        }
00780        *p=0;p++;
00781               /* Here we suppose that nobody can tamper session variable
00782                * file, and do not check variable names against module's
00783                * definition file. Policy under reserve. */
00784            /* We do not allow override though.
00785             * Especially because reply variables should
00786             * be preserved. */
00787        if(strncmp(lbuf,var_prefix,strlen(var_prefix))!=0) 
00788          setenv(lbuf,p,0);
00789        else if(lbuf[strlen(var_prefix)]!=0 && getvar(lbuf+strlen(var_prefix))==NULL) {
00790            if(!isdevelmodule || !try_hack(lbuf+strlen(var_prefix))) {
00791               setvar(lbuf+strlen(var_prefix),p);
00792            }
00793        }
00794     }
00795     close_working_file(&m_file,0);
00796 }
00797 
00798        /* Initialize environment variables according to module's
00799         * variable init or calculation file. 
00800         * init is only used when cmd=new or renew.
00801         * Requires get_var_defs be run first. */
00802 void var_proc(char *fname,int cache)
00803 {
00804     int  t;
00805     char *p, tbuf[MAX_LINELEN+1];
00806 
00807     if(fname!=NULL && read_module_file(fname)) return;
00808     if(untrust&6) get_var_privileges();
00809     while(m_file.linepointer<m_file.linecnt) {
00810        t=m_file.lines[m_file.linepointer].isstart;
00811        if((t&~2)!=1 || m_file.lines[m_file.linepointer].llen==0) {
00812            m_file.linepointer++; continue;
00813        }
00814        wgetline(tbuf,MAX_LINELEN,&m_file); substnest=0;
00815        p=find_word_start(tbuf); if(*p==0) continue;
00816        if((t&2)!=0) exec_main(p+1);
00817        else exec_set(p);
00818     }
00819     close_working_file(&m_file,cache);
00820 }
00821 
00822        /* Deposit the content of wims_deposit into a file */
00823 void var_deposit(char *p)
00824 {
00825     char fn[MAX_FNAME+1];
00826     int l,fd;
00827     if(!trusted_module()) return;
00828     if(deplen>0) l=deplen; else {
00829        while(isspace(*p)) p++; l=strlen(p);
00830     }
00831     if(l<=0) return;
00832     if(l>MAX_DEPOSITLEN) l=MAX_DEPOSITLEN; /* silent truncation, should not occur */
00833     mkfname(fn,"%s/user-deposit",session_prefix);
00834     fd=creat(fn,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if(fd==-1) return;
00835     write(fd,p,l); close(fd);
00836     snprintf(fn,sizeof(fn),"%u",l); setvar("wims_deposit_len",fn);
00837 }
00838 
00839        /* Check and set variables passed in query_string */
00840 void set_vars_from_parm(void)
00841 {
00842     int i,j,al;
00843     char *s, vbuf[MAX_LINELEN+1];
00844     if(forceresume) return;
00845     for(i=0; i<user_var_no; i++) {
00846        j=var_def_check(user_variable[i].name);
00847        if(j<0) continue;
00848             /* check permissions */
00849        al=var_def[j].allow;
00850        if(al != var_allow_any) switch(cmd_type) {
00851            case cmd_new:
00852            case cmd_renew:
00853                if (al != var_allow_init && al != var_allow_config) {
00854 violat:                  /* setvar(error_data_string,user_variable[i].name);
00855                   user_error("allow_violation"); */
00856                   goto loopend;
00857               }
00858                break;
00859            
00860            case cmd_config:
00861                if(al != var_allow_config) goto violat;
00862                break;
00863 
00864            case cmd_reply:
00865               if(al != var_allow_reply) goto violat;
00866                break;
00867            
00868            case cmd_help:
00869               if(al != var_allow_help) goto violat;
00870               break;
00871            
00872            default: goto violat;
00873        }
00874        var_def[j].defined_in_parm=1;
00875        if(strcmp(user_variable[i].name,"wims_deposit")==0) {
00876            var_deposit(user_variable[i].value); continue;
00877        }
00878        mystrncpy(vbuf,user_variable[i].value,sizeof(vbuf));
00879        if(strchr(vbuf,'$')!=NULL) {
00880            char *p;
00881            while((p=strchr(vbuf,'$'))!=NULL) 
00882              string_modify(vbuf,p,p+1,"&#36;");
00883        }
00884        s=getvar(user_variable[i].name);
00885        if(s==NULL || *s==0) setvar(user_variable[i].name, vbuf);
00886        else {  /* concatenate */
00887            int k;
00888            k=strlen(s)+strlen(vbuf);
00889            if(k>=MAX_LINELEN-2) user_error("string_too_long");
00890            snprintf(tmplbuf,sizeof(tmplbuf),"%s, %s",s,vbuf);
00891            setvar(user_variable[i].name, tmplbuf);          
00892        }
00893        loopend: ;
00894     }
00895 }
00896 
00897        /* parms to be eliminated from module_init_parm */
00898 /* char *init_elim[]={
00899     "module","cmd","session","lang","worksheet","wims_access","useropts"
00900 };
00901 #define init_elim_no (sizeof(init_elim)/sizeof(init_elim[0]))
00902 */
00903 
00904 void elim_parm(char *str, char *parm)
00905 {
00906     char *p1, *p2;
00907     for(p1=strstr(str,parm);p1!=NULL;p1=strstr(p1+1,parm)) {
00908        if( (p1>str && *(p1-1)!='&') || *(p1+strlen(parm))!='=')
00909          continue;
00910        p2=strchr(p1,'&');
00911        if(p2==NULL) {
00912            if(p1>str) *(p1-1)=0; else *p1=0;
00913            return;
00914        }
00915        strcpy(p1,p2+1); p1--;
00916     }
00917 }
00918 
00919        /* eliminate technical definitions form parameter string. */
00920 void prep_init_parm(char rqv[])
00921 {
00922     int i;
00923     char *p;
00924 
00925     for(p=strstr(rqv,"&+"); p!=NULL; p=strstr(++p,"&+"))
00926       strcpy(p+1,p+2);
00927     for(i=0;i<RO_NAME_NO;i++) elim_parm(rqv,ro_name[i]);
00928     if(strlen(rqv)>=MAX_LINELEN) rqv[0]=0;
00929     while(rqv[0]=='&') strcpy(rqv,rqv+1);
00930     while(rqv[0]!=0 && rqv[strlen(rqv)-1]=='&') rqv[strlen(rqv)-1]=0;
00931 }
00932 
00933        /* retain initializing parameters, for use in user references */
00934 void set_init_parm(void)
00935 {
00936     char *rq, rqv[MAX_LINELEN*2+2], *u, *sh;
00937     char *shname;
00938     int public_sheet;
00939 
00940     if(isexam) return;
00941     force_setvar("wims_sheet",""); force_setvar("wims_exo","");
00942     rq=getenv("QUERY_STRING");
00943     if(rq==NULL || *rq==0) {
00944        empty:
00945        setvar("module_init_parm",""); return;
00946     }
00947     if(strlen(rq)>=MAX_LINELEN*2) goto empty;
00948     _http2env(rqv,rq); prep_init_parm(rqv);
00949     setvar("module_init_parm",rqv); public_sheet=0;
00950        /* now determine the sheet number for user */
00951     sh=getvar(ro_name[ro_worksheet]); if(sh==NULL) return;
00952     if(*sh=='P') {public_sheet=1; sh++;}
00953     shname="sheet";
00954     u=getvar("wims_user"); if(u==NULL) u="";
00955     if(sh!=NULL && *sh!=0) {
00956        char buf[MAX_LINELEN+1],ubuf[32], nbuf[1024], *c, *m;
00957        char *p1,*p2,*p3,*p4,*p5;
00958        int i,j,sheet;
00959        sheet=atoi(sh); if(sheet<=0 || sheet>256) return;
00960        m=getvar(ro_name[ro_module]);
00961        if(m==NULL) internal_error("set_init_parm(): module name disapears.");
00962        if(*u==0) public_sheet=1;
00963        if(!public_sheet) {
00964            c=getvar("wims_class"); if(c==NULL) c="";
00965            snprintf(nbuf,sizeof(nbuf),"%s/sheets/.%s%d",
00966                    class_dir,shname,sheet);
00967        }
00968        else {
00969            char bf[MAX_LINELEN+1];
00970            int i;
00971            accessfile(bf,"r","%s/.sheets",session_prefix);
00972            if(bf[0]==0) return;
00973            for(i=1, p1=bf;i<sheet;i++,p1=p2) {
00974               p2=strchr(p1,'\n');
00975               if(p2!=NULL) *p2++=0; else p2=p1+strlen(p1);
00976            }
00977            p2=strchr(p1,'\n'); if(p2) *p2=0;
00978            snprintf(nbuf,sizeof(nbuf),"bases/sheet/%s.def",p1);
00979        }
00980        if(readfile(nbuf,buf,sizeof(buf))==NULL) return;
00981        for(p1=strstr(buf,"&+");p1!=NULL;p1=strstr(++p1,"&+"))
00982            strcpy(p1+1,p1+2);
00983        if(strncmp(m,"classes/",strlen("classes/"))==0) {
00984            m="classes/";
00985            for(p1=strstr(buf,":classes/");p1;p1=strstr(p1+1,":classes/")) {
00986               if(p1==buf || *(p1-1)=='\n') {
00987                   p1+=strlen(":classes/");
00988                   p2=find_word_end(p1); if(p2>p1 && *p2=='\n') strcpy(p1,p2);
00989               }
00990            }
00991        }
00992        snprintf(nbuf,sizeof(nbuf),":%s\n%s\n",m,rqv);
00993        p1=strstr(buf,nbuf);
00994        while(p1>buf && *(p1-1)!='\n') p1=strstr(p1+1,nbuf);
00995        if(p1!=NULL) {
00996            p2=strchr(buf,':');
00997            while(p2>buf && *(p2-1)!='\n') p2=strchr(p2+1,':');
00998            for(i=1;p2!=NULL && p2<p1;i++) {
00999               p2=strchr(p2+1,':');
01000               while(p2>buf && *(p2-1)!='\n') p2=strchr(p2+1,':');
01001            }
01002            if(p2==NULL) return;    /* error which should not occur */
01003            snprintf(ubuf,sizeof(ubuf),"%d",i);
01004               /* look for dependency information */
01005            for(j=0, p3=strchr(p1+strlen(nbuf),'\n');
01006               j<3 && p3 && *(p3+1)!=':';
01007               j++, p3=strchr(p3+1,'\n'));
01008            if(j>=3 && p3!=NULL && *(p3+1)!=':') {
01009               p3++; p4=strchr(p3,'\n');
01010               if(p4) {
01011                   *p4++=0; if(*p4!=':') { /* options */
01012                      p5=strchr(p4,'\n'); if(p5) *p5=0;
01013                      force_setvar("wims_exoption",p4);
01014                   }
01015               }
01016               p3=find_word_start(p3);     strip_trailing_spaces(p3);
01017                      /* non-empty dependency information */
01018               if(*p3 && !public_sheet) {
01019                   exodepOK=depcheck(sh,i,p3);
01020                   if(!exodepOK) setvar("wims_exodep","pending");
01021               }
01022            }
01023            if(public_sheet) {
01024               char bf[32];
01025               snprintf(bf,16,"P%s",sh);
01026               force_setvar("wims_sheet",bf);
01027            }
01028            else force_setvar("wims_sheet",sh);
01029            force_setvar("wims_exo",ubuf);
01030            wims_sheet=sheet; wims_exo=i;
01031        }
01032     }
01033 }
01034 
01035        /* user with class: whether exercise is registered
01036         * Returns 1 if got, 0 otherwise. */
01037 int get_parmreg(void)
01038 {
01039     char *p, *cl, *u, nbuf[MAX_FNAME+1];
01040     struct stat st;
01041 
01042     u=getvar("wims_user"); cl=getvar("wims_class");
01043     if(u==NULL || cl==NULL || *u==0 || *cl==0 || strcmp(u,"supervisor")==0
01044        || wims_sheet<=0 || wims_exo<=0) return 0;
01045     mkfname(nbuf,"%s/.parmreg/%s.%d.%d", class_dir,u,wims_sheet,wims_exo);
01046     p=getvar("wims_scorereg"); if(p!=NULL && strcmp(p,"suspend")==0) {
01047        unlink(nbuf); return 0;
01048     }
01049     if(stat(nbuf,&st)) return 0;
01050        /* latency is 10 min. */
01051     if(st.st_mtime<nowtime-600 || st.st_mtime > nowtime) {
01052        unlink(nbuf); return 0;
01053     }
01054     if(open_working_file(&m_file,nbuf)!=0) return 0;
01055     mkfname(m_file.name,"parmreg/%s.%d.%d",u,wims_sheet,wims_exo);
01056     while(wgetline(tmplbuf,MAX_LINELEN, &m_file)!=EOF) {
01057        p=strchr(tmplbuf,'='); 
01058        if(p==NULL || p<=tmplbuf || isspace(tmplbuf[0]) )
01059                      /* this time it is corrupted var file */
01060          internal_error("get_parmreg(): corrupt parmreg file.");
01061        *p=0;p++; 
01062        if(strncmp(tmplbuf,var_prefix,strlen(var_prefix))!=0) setenv(tmplbuf,p,1);
01063        else if(tmplbuf[strlen(var_prefix)]!=0) force_setvar(tmplbuf+strlen(var_prefix),p);
01064     }
01065     parm_restore=1;
01066     close_working_file(&m_file,0); return 1;
01067 }
01068 
01069        /* set environment variables */
01070 void set_variables(void)
01071 {
01072     outputing=0; readnest=0;
01073     get_var_defs();
01074     set_vars_from_parm();
01075     if(cmd_type != cmd_new && cmd_type != cmd_renew) set_vars_from_session();
01076     else {
01077        set_init_parm();
01078        if(wims_sheet>0 && get_parmreg()) {
01079            cmd_type=cmd_resume; force_setvar("cmd","resume");
01080            var_proc(main_var_proc_file,0); return;
01081        }
01082        checkrafale();
01083        var_proc(var_init_file,0);
01084     }
01085     /* check_var_bounds(); */
01086     var_proc(main_var_proc_file,0);
01087 }
01088 
01089        /* Output a phtml file. */
01090 void phtml_put(char *fname,int cache)
01091 {
01092     int t;
01093     char tbuf[MAX_LINELEN+1];
01094 
01095     outputing=1;
01096      /* File not found; we give empty output, but no error message. */
01097     if(fname!=NULL && read_module_file(fname)!=0) return;
01098     if(untrust&6) get_var_privileges();
01099     while(m_file.linepointer<m_file.linecnt) {
01100        t=m_file.lines[m_file.linepointer].isstart;
01101        if((t&~18)!=1) {m_file.linepointer++; continue;}
01102        wgetline(tbuf,MAX_LINELEN,&m_file); substnest=0;
01103        if((t&2)!=0) {exec_main(tbuf+1); continue;}
01104        substit(tbuf); output0(tbuf); _output_("\n");
01105     }
01106     close_working_file(&m_file,cache);
01107 }
01108 
01109        /* output a file in base html directory. Internal use only. */
01110 void phtml_put_base(char *fname,int cache)
01111 {
01112     WORKING_FILE save;
01113     char modsave[MAX_FNAME+1];
01114     memmove(&save,&m_file,sizeof(WORKING_FILE));
01115     mystrncpy(modsave,module_prefix,sizeof(modsave));
01116     strcpy(module_prefix,"html");
01117     phtml_put(fname,cache);
01118     mystrncpy(module_prefix,modsave,sizeof(module_prefix));
01119     memmove(&m_file,&save,sizeof(WORKING_FILE));
01120 }
01121 
01122        /* Read main.phtml, process it, and write to stdout. */
01123 void main_phtml_put(char *mname)
01124 {
01125     char *p, buf[1024], txbuf[256], bgbuf[256];
01126     char *bcolor, *refcolor, *bg, *tx;
01127     define_html_header(); readnest=0;
01128     nph_header(200);
01129     p=getvar("wims_backslash_insmath");
01130     if(p!=NULL && strcasecmp(p,"yes")==0) backslash_insmath=1;
01131     p=getvar("wims_expire");
01132     if(p!=NULL) p=strstr(p,"no-cache");
01133     if(p!=NULL) _output_("Cache-Control: no-cache\r\nPragma: no-cache\r\n");
01134     output("Server: %s %s (%s)\n", SHORTSWNAME,wims_version,LONGSWNAME);
01135     if(!robot_access && strcasecmp(usecookie,"yes")==0 && setcookie
01136        && mode!=mode_popup) {
01137        if(cookieset[0]==0) {
01138            p=getvar("wims_sescookie");
01139            if(p!=NULL && *p!=0) mystrncpy(cookieset,p,sizeof(cookieset));
01140        }
01141        output("Set-Cookie: %s%s; path=/\r\n",cookieheader,cookieset);
01142     }
01143     p=getvar("wims_main_font");
01144     if(p!=NULL && *p!=0) output("Content-type: text/html; charset=%s\r\n\r\n",p);
01145     else _output_("Content-type: text/html\r\n\r\n");
01146     bcolor=getvar("wims_bgcolor");
01147     if(bcolor==NULL || *bcolor==0) bcolor=bgcolor;
01148     refcolor=getvar("wims_ref_bgcolor");
01149     if(refcolor==NULL || *refcolor==0) {
01150        setvar("wims_ref_bgcolor","white");
01151        refcolor="white";
01152     }
01153     bg=getvar("wims_bgimg"); bgbuf[0]=0;
01154     if(bg!=NULL && *bg!=0 && strchr(bg,'\"')==NULL) {
01155        if(strchr(bg,'/')==NULL)
01156          snprintf(bgbuf,sizeof(bgbuf),"background=\"gifs/bg/%s\"",bg);
01157        else
01158          snprintf(bgbuf,sizeof(bgbuf),"background=\"%s\"",bg);
01159     }
01160     tx=getvar("wims_textcolor");
01161     if(tx!=NULL && *tx!=0 && strchr(tx,'\"')==NULL) {
01162        snprintf(txbuf,sizeof(txbuf),"text=\"%s\"",tx);
01163     }
01164     else txbuf[0]=0;
01165     snprintf(buf,sizeof(buf),
01166             "bgcolor=\"%s\" %s %s",
01167             bcolor,txbuf, bgbuf);
01168     setvar("wims_htmlbody",buf);
01169     phtml_put(mname,0);
01170 }
01171 
01172 void _write_var(char *name, FILE *varf,int user,int skip)
01173 {
01174     char *s, buf[MAX_NAMELEN+9], nbf[MAX_NAMELEN+9];
01175 
01176     if((user&2)!=0) {
01177        snprintf(nbf,sizeof(nbf),"%s%s",wims_prefix,name); name=nbf;
01178     }
01179     if((user&1)!=0) {
01180        snprintf(buf,sizeof(buf),"%s%s",var_prefix,name); s=_getvar(name);
01181     }
01182     else {
01183        mystrncpy(buf,name,sizeof(buf)); s=getenv(name);
01184     }
01185     if(s==NULL) s="";
01186     if(skip && *s==0) return;
01187     fprintf(varf,"%s=",buf);
01188     if(strchr(s,'\n')==NULL) fputs(s,varf);
01189     else while(*s) {
01190          if(*s=='\n') fputc('\\',varf);
01191          fputc(*s,varf); s++;
01192     }
01193     fputc('\n',varf);
01194 }
01195 
01196 void _write_vars(FILE *varf)
01197 {
01198     int i,j,k;
01199     char nbuf[MAX_NAMELEN+1];
01200     for(i=0;i<defined_var_total;i++) {
01201        if(var_def[i].beg>=0) {
01202            if(var_def[i].end<=var_def[i].beg) {
01203               snprintf(nbuf,sizeof(nbuf),"%s%d",var_def[i].name,var_def[i].beg);
01204               _write_var(nbuf,varf,1,1);
01205            }
01206            else {
01207               char *pbuf[MAX_VAR_NUM];
01208               j=varsuite(var_def[i].name,var_def[i].beg,var_def[i].end,pbuf,MAX_VAR_NUM);
01209               for(k=0;k<j;k++) _write_var(pbuf[k],varf,1,1);
01210            }
01211        }
01212        else _write_var(var_def[i].name,varf,1,1);
01213     }
01214 }
01215 
01216        /* save exercise parm for registered users */
01217 void save_parmreg(void)
01218 {
01219     char *p, *u, *sh, *ex, nbuf[MAX_FNAME+1], dbuf[MAX_FNAME+1];
01220     int s;
01221     FILE *varf;
01222 
01223     if(cmd_type!=cmd_reply && cmd_type!=cmd_new && cmd_type!=cmd_renew)
01224       return;
01225     u=getvar("wims_user");
01226     if(class_dir[0]==0 || *u==0) return;
01227     sh=getvar("wims_sheet"); ex=getvar("wims_exo");
01228     if(sh==NULL || ex==NULL || *sh==0 || *ex==0) return;
01229     mkfname(nbuf,"%s/.parmreg/%s.%s.%s",
01230             class_dir,u,sh,ex);
01231     if(cmd_type==cmd_reply) {
01232        unlink(nbuf); return;
01233     }
01234     p=getvar("wims_scorereg");
01235     if(p!=NULL && strcmp(p,"suspend")==0) return;
01236        /* these two lines must be before random factor 
01237         * in order to set variable wims_scoring */
01238     s=atoi(sh); if(getscorestatus(getvar("wims_class"),s)==0) return;
01239     if(strcmp(u,"supervisor")==0) return;
01240        /* 0.2 is random factor to trigger exercise parm register */
01241 /*    return;
01242 */    if((double) random()>(double) RAND_MAX*0.2) return;
01243     mkfname(dbuf,"%s/.parmreg",class_dir);
01244     mkdirs(dbuf); varf=fopen(nbuf,"w"); if(varf==NULL) return;
01245     _write_var("module_init_parm",varf,1,0);
01246     _write_var("wims_sheet",varf,1,1);
01247     _write_var("wims_exo",varf,1,1);
01248     _write_var("wims_scoring",varf,1,1);
01249     _write_vars(varf);
01250     fclose(varf);
01251 }
01252 
01253 void exolog(char *fname)
01254 {
01255     FILE *varf;
01256     varf=fopen(fname,"a");
01257     if(varf!=NULL) {
01258               /* The first 4 lines should not be modified */
01259        fprintf(varf,"\n:\n");
01260        _write_var("QUERY_STRING",varf,0,0);
01261        _write_var("module",varf,1,0);
01262        _write_var("cmd",varf,1,0);
01263        _write_var("module_init_parm",varf,1,0);
01264        _write_var("wims_scoring",varf,1,1);
01265        _write_var("module_score",varf,1,1);
01266        fprintf(varf,"w_wims_checktime1=%lu\n\
01267 w_wims_checktime2=%s\n",nowtime,nowstr);
01268        _write_vars(varf);
01269        fclose(varf);
01270     }
01271 }
01272        /* save variables to session var file */
01273 void save_session_vars(void)
01274 {
01275     int i;
01276     char *mp, *sh, *ex, *ll;
01277     FILE *varf;
01278        /* light pages don't need saved variables. ? */
01279 /*    if(varchr(module_prefix,"light")!=NULL) return;
01280 */
01281     if(robot_access) return;
01282        /* no variable saving if cmd=help? */        
01283     if(cmd_type==cmd_help) return;
01284     lastdatafile[0]=lastftest[0]=0;
01285     lessrafale();
01286     mp=getvar("wims_nextmodule"); if(mp!=NULL && *mp!=0) {
01287        mp=getvar("module"); if(strcmp(mp,home_module)==0) 
01288          force_setvar("module",getvar("wims_nextmodule"));
01289     }
01290     varf=fopen_session_var_file("w");
01291     for(i=0;i<HEADER_VAR_NO;i++)
01292       _write_var(header_var_name[i],varf,0,0);
01293     for(i=0;i<RO_NAME_NO;i++)
01294       _write_var(ro_name[i],varf,1,0);
01295     for(i=0;i<INTERNAL_NAME_NO;i++) {
01296        if(internal_name[i].stat==0)
01297          _write_var(internal_name[i].name,varf,3,0);
01298     }
01299     _write_var("password",varf,0,1);
01300     save_parmreg();
01301     if(new_session) fprintf(varf,"wims_new_session=yes\n");
01302     fprintf(varf,"\n");
01303     _write_var("module_init_parm",varf,1,0);
01304     _write_var("wims_sheet",varf,1,1);
01305     _write_var("wims_exo",varf,1,1);
01306     _write_var("wims_scoring",varf,1,1);
01307     _write_vars(varf);
01308     fclose(varf);
01309     if(cmd_type==cmd_new || cmd_type==cmd_renew || cmd_type==cmd_reply || cmd_type==cmd_next) {
01310        ll=getvar("wims_class_examlog");
01311        if(ll!=NULL && *ll!=0) i=atoi(ll); else i=examlog_limit;
01312        if(strstr(session_prefix,"_exam")!=NULL && examlogf[0]!=0 &&
01313           simuxam==0 && i>0) {
01314            mkdirs(examlogd); exolog(examlogf);
01315        }
01316        else {
01317            ll=getvar("wims_class_exolog");
01318            sh=getvar("wims_sheet"); ex=getvar("wims_exo"); 
01319            if(ll!=NULL && atoi(ll)>0 && 
01320               sh!=NULL && *sh!=0 && ex!=NULL && *ex!=0) {
01321               char buf[MAX_FNAME+1];
01322               mkfname(buf,"%s/exolog.%s.%s",session_prefix,sh,ex);
01323               if(cmd_type==cmd_new || cmd_type==cmd_renew) unlink(buf);
01324               exolog(buf);
01325            }
01326        }
01327     }
01328     if(var_def_buf) free(var_def_buf);
01329 }
01330