Subversion Repositories wimsdev

Rev

Rev 18000 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
  2.  *
  3.  *  This program is free software; you can redistribute it and/or modify
  4.  *  it under the terms of the GNU General Public License as published by
  5.  *  the Free Software Foundation; either version 2 of the License, or
  6.  *  (at your option) any later version.
  7.  *
  8.  *  This program is distributed in the hope that it will be useful,
  9.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  *  GNU General Public License for more details.
  12.  *
  13.  *  You should have received a copy of the GNU General Public License
  14.  *  along with this program; if not, write to the Free Software
  15.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  */
  17. /* routines to process variables */
  18.  
  19. #include "wims.h"
  20. char *computed_var_start; /* pointer to read-in var def file */
  21. int session_var_ready=0;
  22. char last_host[32]="";
  23. char *robotcheck="";
  24.  
  25. char *header_var_name[]={
  26.     "REMOTE_ADDR", "HTTP_REFERER", "QUERY_STRING", "HTTP_USER_AGENT",
  27.      "HTTP_COOKIE"
  28. };
  29. #define HEADER_VAR_NO (sizeof(header_var_name)/sizeof(header_var_name[0]))
  30.  
  31. struct special_name {char *name; int value;} special_name[]={
  32.   {"MAX_EXAMS",MAX_EXAMS},
  33.   {"MAX_EXOS",MAX_EXOS},
  34.   {"MAX_FREEWORKS",MAX_FREEWORKS},
  35.   {"MAX_LTECHVAR",MAX_LTECHVAR},
  36.   {"MAX_OEFCHOICES",MAX_OEFCHOICES},
  37.   {"MAX_OEFREPLIES",MAX_OEFREPLIES},
  38.   {"MAX_SHEETS",MAX_SHEETS},
  39.   {"MAX_TECHVARVAL",MAX_TECHVARVAL},
  40.   {"MAX_USERFORGRADES",MAX_USERFORGRADES},
  41.   {"MAX_VOTES",MAX_VOTES},
  42. };
  43. int special_name_no=(sizeof(special_name)/sizeof(special_name[0]));
  44. char *var_allow[]={
  45.     "deny" , "init" , "config" ,
  46.       "reply", "any", "help"
  47. };
  48. enum {
  49.     var_allow_deny, var_allow_init, var_allow_config,
  50.       var_allow_reply, var_allow_any, var_allow_help
  51. } VAR_ALLOWS;
  52. #define VAR_ALLOW_NO (sizeof(var_allow)/sizeof(var_allow[0]))
  53.  
  54. struct internal_name internaldef_name[]={
  55.   {"exotrymax",var_allow_init}
  56. };
  57. int INTERNALDEF_NAME_NO=(sizeof(internaldef_name)/sizeof(internaldef_name[0]));
  58.  
  59. /* install a temporary directory for the session */
  60. void mktmpdir(char *p)
  61. {
  62.   char *base;
  63.   if(p==NULL || *p==0 || strstr(p,"robot")!=NULL) return;
  64.   if(strstr(tmp_dir,"sessions")!=NULL) return;
  65.   if(ftest("../chroot/tmp/sessions/.chroot")==is_file) base="chroot/tmp";
  66.   else base="tmp";
  67.   mkfname(tmp_dir,"../%s/sessions/%s",base,p);
  68.   remove_tree(tmp_dir); mkdirs(tmp_dir);
  69.   chmod(tmp_dir,S_IRUSR|S_IWUSR|S_IXUSR
  70.        |S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
  71.   setenv("tmp_dir",tmp_dir,1); setenv("TMPDIR",tmp_dir,1);
  72. }
  73.  
  74. /* Open session variable file */
  75. FILE *fopen_session_var_file(char read_or_write[])
  76. {
  77.   char *nbuf; FILE *f;
  78.  
  79.   nbuf=mkfname(NULL,"%s/var",session_prefix);
  80.   if(read_or_write[0]=='r') {
  81.     if(open_working_file(&m_file,nbuf)!=0) return NULL;
  82.     mkfname(m_file.name,"session_var");
  83.     return stdin;
  84.   }
  85.   f=fopen(nbuf,read_or_write);
  86.   if(f==NULL) {
  87. /* expired_session */
  88.     internal_error("fopen_session_var_file(): unable to create session variable file.");
  89.   }
  90.   mkfname(m_file.name,"session_var");
  91.   m_file.l=0;
  92.   return f;
  93. }
  94.  
  95. /* Open a module file, read only, with name checking.
  96.  * returns NULL if error.
  97.  */
  98. int read_module_file(char *fname)
  99. {
  100.   char nbuf[MAX_FNAME+1];
  101.  
  102.   if(get_cached_file(fname)>=0) return 0;
  103.   if(find_module_file(fname,nbuf,0)) return -1;
  104.   if(open_working_file(&m_file,nbuf)!=0) return -1;
  105.   untrust|=(untrust>>8);
  106.   mystrncpy(m_file.name,fname,sizeof(m_file.name));
  107.   if(strncmp(module_prefix,module_dir,strlen(module_dir))!=0) m_file.nocache|=8;
  108.   return 0;
  109. }
  110. /* list of variables get from the query parms */
  111. int varget[]={ro_module,ro_lang,ro_useropts,ro_worksheet};
  112. #define varget_no (sizeof(varget)/sizeof(varget[0]))
  113.  
  114. /* set up ref strings according to protocol */
  115. void set_protocol(void)
  116. {
  117.   if(strcmp(protocol,"https")!=0) return;
  118.   if(strncmp(ref_name,"http:",5)==0) {
  119.     string_modify(ref_name,ref_name+4,ref_name+4,"s");
  120.     string_modify(ref_base,ref_base+4,ref_base+4,"s");
  121.     force_setvar("wims_ref_name",ref_name);
  122.   }
  123. }
  124.  
  125. /* verify class participant connection data */
  126. void classlock(void)
  127. {
  128.   int lvl;
  129.   char *p;
  130.  
  131.   p=getvar("wims_classlock"); if(p==NULL) lvl=0; else {
  132.     p=find_word_start(p);
  133.     lvl=*p-'0'; if(lvl<0 || lvl>7) lvl=0;
  134.   }
  135.   if(lvl==7) { /* closed */
  136.     p=getvar("wims_user");
  137.     if(p==NULL || strcmp(p,"supervisor")!=0) user_error("class_closed");
  138.   }
  139.   if(lvl==2 || lvl==4 || lvl==6) { /* https */
  140.     p=getenv("HTTPS");
  141.     if(p==NULL || strcasecmp(p,"on")!=0) user_error("need_https");
  142.   }
  143.   if(lvl==3 || lvl>=5) {
  144.     if(strcmp(last_host,remote_addr)!=0) user_error("bad_host");
  145.   }
  146.   if((lvl==1 || lvl>=4) && cookiegot[0]==0) { /* cookie */
  147.     setcookie=1;
  148.     setvar("cookie_module",getvar(ro_name[ro_module]));
  149.     setvar("cookie_cmd",getvar(ro_name[ro_cmd]));
  150.     force_setvar(ro_name[ro_module],home_module);
  151.     force_setvar(ro_name[ro_cmd],commands[cmd_new]);
  152.     setvar("wims_askcookie","yes");
  153.     return;
  154.   }
  155.   else setcookie=0;
  156. }
  157.  
  158. /* get static session variables */
  159. void get_static_session_var(void)
  160. {
  161.   char *p, *pe, *p2, *p3;
  162.   char sbuf[MAX_FNAME+1], tbuf[MAX_LINELEN+1];
  163.   mystrncpy(sbuf,session_prefix,sizeof(sbuf));
  164.   for(p=sbuf+strlen(sbuf);p>sbuf && *p!='_' && *p!='/'; p--);
  165.   if(p>sbuf && *p=='_') *p=0;
  166.   accessfile(tbuf,"r","%s/var.stat",sbuf);
  167.   p=strrchr(sbuf,'/'); if(p!=NULL) p++; else p=sbuf;
  168.   mktmpdir(p);
  169.   for(p=find_word_start(tbuf);*p;p=find_word_start(pe)) {
  170.     pe=strchr(p,'\n'); if(pe!=NULL) *pe++=0; else pe=p+strlen(p);
  171.     p2=strchr(p,'='); if(p2==NULL) continue;
  172.     *p2++=0; force_setvar(p,p2);
  173.   }
  174.   p=getvar("wims_class"); if(p==NULL || *p==0) return;
  175.   mkfname(class_dir,"%s/%s",class_base,p);
  176.   classlock();
  177.   p3=getvar("wims_class_refcolor");
  178.   if(p3!=NULL && *p3!=0) force_setvar("wims_ref_bgcolor",p3);
  179.   p3=getvar("wims_class_ref_menucolor");
  180.   if(p3!=NULL && *p3!=0) force_setvar("wims_ref_menucolor",p3);
  181.   p3=getvar("wims_class_ref_button_color");
  182.   if(p3!=NULL && *p3!=0) force_setvar("wims_ref_button_color",p3);
  183.   p3=getvar("wims_class_ref_button_bgcolor");
  184.   if(p3!=NULL && *p3!=0) force_setvar("wims_ref_button_bgcolor",p3);
  185.   p3=getvar("wims_class_ref_button_help_bgcolor");
  186.   if(p3!=NULL && *p3!=0) force_setvar("wims_ref_button_help_bgcolor",p3);
  187.   p3=getvar("wims_class_ref_button_help_color");
  188.   if(p3!=NULL && *p3!=0) force_setvar("wims_ref_button_help_color",p3);
  189.   p2=getvar(ro_name[ro_module]);
  190.   if(p2==NULL || strncmp(p2,"classes/",strlen("classes/"))!=0) return;
  191.   mkfname(sbuf,"classes/%s",lang);
  192.   if(strcmp(sbuf,p2)!=0) force_setvar(ro_name[ro_module],sbuf);
  193. }
  194.  
  195. /* set one static session variable */
  196. void set_static_session_var(char *name, char *val)
  197. {
  198.   char *p;
  199.   char sbuf[MAX_FNAME+1], tbuf[MAX_LINELEN+1];
  200.   mystrncpy(sbuf,session_prefix,sizeof(sbuf));
  201.   for(p=sbuf+strlen(sbuf);p>sbuf && *p!='_' && *p!='/'; p--)
  202.   ;
  203.   if(p>sbuf && *p=='_') *p=0;
  204.   snprintf(sbuf+strlen(sbuf),sizeof(sbuf)-strlen(sbuf),"/var.stat");
  205.   snprintf(tbuf,sizeof(tbuf),"%s=%s",name,val);
  206.   setdef(sbuf,tbuf); setvar(name,val);
  207. }
  208.  
  209. /* The session is probably robot. */
  210. void robot_doubt(void)
  211. {
  212.   char *h, *p;
  213.  
  214.   p=getvar("special_parm"); h=getvar("module");
  215.   if(p==NULL || h==NULL) {
  216.     bad: user_error("robot_doubt"); return;
  217.   }
  218.   p=find_word_start(p); strip_trailing_spaces(p);
  219.   if(strcmp(p,"wims")!=0 || strcmp(h,home_module)!=0) goto bad;
  220.   set_static_session_var("wims_robotcheck","manual");
  221. }
  222.  
  223. /* User has changed module within an operation.
  224.  * Probably due to robot access.
  225.  */
  226. void bad_module(void)
  227. {
  228.   char *p;
  229.   p=getvar("wims_user"); if(p==NULL) p="";
  230.   if(*p==0 && strcmp(robotcheck,"manual")!=0) set_static_session_var("wims_robotcheck","robot");
  231.   else setvar("wims_human_access","yes");
  232.   user_error("module_change");
  233. }
  234.  
  235. /* returns 1 if session directory exists */
  236. int session_exists(char *s)
  237. {
  238.   if(ftest(mkfname(NULL,"../%s/%s/var",SESSION_BASE,s))==is_file) return 1;
  239.   else return 0;
  240. }
  241.  
  242. /* Check the validity of session number .
  243.  * returns 0 if OK, else -1.
  244.  */
  245. int check_session(void)
  246. {
  247.   char tbuf[MAX_LINELEN+1], vbuf[MAX_LINELEN+1];
  248.   char *p, *pp, *pr;
  249.   int i,m,n,pl,rapid,badmod;
  250.   struct stat st;
  251.  
  252.   rapid=badmod=0; pr="";
  253.   if(fopen_session_var_file("r")==NULL) return -1;
  254.   if(ftest(s2_prefix)!=is_dir) mkdirs(s2_prefix);
  255.   session_var_ready=1; memmove(&svar_file,&m_file,sizeof(WORKING_FILE));
  256. /* REMOTE_ADDR */
  257.   wgetline(vbuf,MAX_LINELEN,&m_file);
  258.   mystrncpy(last_host,vbuf+strlen("REMOTE_ADDR="),sizeof(last_host));
  259.   m_file.linepointer++; /* now it points to query_string */
  260.   pp=getenv("QUERY_STRING");
  261.   if(pp!=NULL && *pp!=0 && strlen(pp)<=MAX_LINELEN) {
  262. /* we compare the query string with the last one. */
  263.     char *p1, *p2;
  264.     wgetline(tbuf,MAX_LINELEN,&m_file);
  265.     p1=tbuf+strlen("QUERY_STRING=");
  266.     if(strncmp(tbuf,"QUERY_STRING=",strlen("QUERY_STRING="))==0 &&
  267.         strcmp(pp,p1)==0 && strstr(session_prefix,"_test")==NULL) {
  268. /* query string does not change */
  269.       if(ftest(mkfname(NULL,"%s/%s",s2_prefix,lastout))==is_file &&
  270.             ftest_size > 0) {
  271.         uselast:
  272.         putlastout(); delete_pid(); exit(0);
  273.       }
  274.       else {
  275.         if(cmd_type==cmd_new || cmd_type==cmd_renew ||
  276.              cmd_type==cmd_reply || cmd_type==cmd_next) {
  277.           cmd_type=cmd_resume;
  278.           force_setvar(ro_name[ro_cmd],"resume");
  279.           forceresume=1;
  280.         }
  281.       }
  282.     }
  283. /* stop rapidfire requests */
  284.     if((cmd_type==cmd_new || cmd_type==cmd_renew) &&
  285.         strncmp(p1,"session=",strlen("session="))==0 &&
  286.         strncmp(pp,"session=",strlen("session="))==0) {
  287.       p1=strchr(p1,'&'); if(p1==NULL) p1="";
  288.       p2=strchr(pp,'&'); if(p2==NULL) p2=""; pr=p2;
  289.       if(strcmp(p1,p2)==0) rapid=1;
  290.     }
  291.   }
  292.   m_file.linepointer=3;
  293.   wgetline(vbuf,MAX_LINELEN,&m_file); /* stored user_agent */
  294. /*    p=getenv("HTTP_USER_AGENT"); if(p==NULL) p="";
  295.     if(strcmp(vbuf+strlen("HTTP_USER_AGENT="),p)!=0) bad_ident(); */
  296.   m_file.linepointer=HEADER_VAR_NO;
  297.   pl=strlen(var_prefix);i=-1;
  298.   while(wgetline(tbuf,MAX_LINELEN,&m_file)!=EOF) {
  299.     if(tbuf[0]==0) break; /* blank line */
  300.     if(strncmp(tbuf,var_prefix,pl)!=0) break;
  301.     i++;if(i>=RO_NAME_NO) break;
  302.     for(n=0;n<varget_no && varget[n]!=i;n++)
  303.     ;
  304.       if(n>=varget_no) continue;
  305.     m=pl+strlen(ro_name[i]);
  306.     if(tbuf[m]!='=' || tbuf[m+1]==0) continue;
  307.     if(i==ro_module && cmd_type!=cmd_new && cmd_type!=cmd_intro && cmd_type!=cmd_help) {
  308.       char *pp;
  309.       pp=getvar(ro_name[i]);
  310.       if(pp!=NULL && *pp!=0 && strcmp(pp,tbuf+m+1)!=0) badmod=1;
  311.     }
  312.     if(i==ro_lang && !user_lang)
  313.       force_setvar(ro_name[i],tbuf+m+1);
  314.     else setvar(ro_name[i],tbuf+m+1);
  315.   }
  316. /* recover internal variables */
  317.   do
  318.   {
  319.     char *v;
  320.     if(tbuf[0]==0) break;
  321.     v=strchr(tbuf,'=');
  322.     if(v==NULL) break; else *(v++)=0;
  323.     if(strncmp(tbuf,var_prefix,strlen(var_prefix))!=0) setenv(tbuf,v,1);
  324.     else if(tbuf[strlen(var_prefix)]) force_setvar(tbuf+strlen(var_prefix),v);
  325.   }
  326.   while(wgetline(tbuf,MAX_LINELEN,&m_file)!=EOF);
  327.   get_static_session_var();
  328.   robotcheck=getvar("wims_robotcheck"); if(robotcheck==NULL) robotcheck="";
  329. /* form access means manual access. Mark this. */
  330.   if(form_access && strcmp(robotcheck,"manual")!=0) {
  331.     robotcheck="manual";
  332.     set_static_session_var("wims_robotcheck","manual");
  333.   }
  334.   else if(strcmp(robotcheck,"robot")==0) robot_doubt();
  335.   if(badmod) bad_module();
  336.   if(cookiegot[0]!=0) {
  337.     p=getvar("wims_sescookie");
  338.     if(p!=NULL && *p!=0 && strcmp(cookiegot,p)!=0) bad_ident();
  339.   }
  340.   p=getvar("wims_sreferer");
  341.   if(p!=NULL && *p!=0) {
  342.     setenv("HTTP_REFERER",p,1); setvar("httpd_HTTP_REFERER",p);
  343.   }
  344.   if(rapid) {
  345.     int rapidfiredelay;
  346.     char *pw, fnbuf[MAX_FNAME+1];
  347. /* Delay: 10 seconds within worksheets, 1 second otherwise. */
  348.     pw=getvar("wims_developer");
  349.     if(pw!=NULL && *pw!=0) goto delcheckend;
  350.     pw=getvar("wims_user");
  351.     if(pw==NULL || *pw==0 || strcmp(pw,"supervisor")==0) rapidfiredelay=1;
  352.     else {
  353.       pw=strstr(pr,"&+worksheet=");
  354.       if(pw!=NULL && myisdigit(*(pw+strlen("&+worksheet=")))) rapidfiredelay=10;
  355.         else rapidfiredelay=2;
  356.     }
  357.     if(ftest(mkfname(fnbuf,"%s/%s",s2_prefix,lastout))==is_file
  358.         && ftest_size > 0
  359.         && stat(fnbuf,&st) == 0
  360.         && st.st_mtime > nowtime-rapidfiredelay && st.st_mtime <= nowtime)
  361.       goto uselast;
  362.   }
  363. /* set protocol string */
  364.   delcheckend: pp=getvar("wims_protocol");
  365.   if(pp!=NULL && strcmp(pp,"https")==0) {
  366.     protocol="https"; set_protocol();
  367.   }
  368.   useropts(); return 0;
  369. }
  370. /* check whether a session is trapped. */
  371. void trap_check(char *s)
  372. {
  373.   char buf[64];
  374.   char *p;
  375.   time_t t1;
  376.  
  377.   setvar("wims_session_expired",s);
  378.   accessfile(tmplbuf,"r","../tmp/log/trap.check");
  379.   if(tmplbuf[0]==0) return;
  380.   p=getenv("REMOTE_ADDR");if(p==NULL) return;
  381.   snprintf(buf,sizeof(buf),":%s,%s,",s,p);
  382.   p=strstr(tmplbuf,buf); if(p==NULL) return;
  383.   p+=strlen(buf);*find_word_end(p)=0;
  384.   t1=atoi(p);
  385.   if(t1>nowtime) user_error("trapped");
  386. }
  387.  
  388. char cars[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  389.  
  390. void set_cookie(void)
  391. {
  392.   #define keylen 20
  393.   char sesbuf[16], keybuf[keylen+8];
  394.   char *p;
  395.  
  396.   p=getvar(ro_name[ro_session]); if(p==NULL) return;
  397.   mystrncpy(sesbuf,p,sizeof(sesbuf));
  398.   if(strchr(sesbuf,'_')==NULL) { /* main session */
  399.     int i;
  400.     for(i=0;i<keylen;i++) keybuf[i]=cars[random()%36];
  401.     keybuf[keylen]=0; cookiegot[0]=0;
  402.     snprintf(cookieset,sizeof(cookieset),"%s-%s",sesbuf,keybuf);
  403.     set_static_session_var("wims_sescookie",cookieset);
  404.     setcookie=1;
  405.   }
  406.   else { /* subsession */
  407.     p=getvar("wims_sescookie"); if(p && *p)
  408.     mystrncpy(cookieset,p,sizeof(cookieset));
  409.   }
  410. }
  411.  
  412. /* create a session number */
  413. void create_session(void)
  414. {
  415.   long t; char session_str[64],*s;
  416.   char *p, ses_dir_buf[MAX_FNAME+1], sesrandbuf[MAX_LINELEN+1];
  417.   int i;
  418.  
  419. /* no session is created for robots */
  420.   if(robot_access) return;
  421.   sesrandbuf[0]=0;
  422. /* If session is given in request_string: use it. */
  423.   s=getvar(ro_name[ro_session]); if(s==NULL) goto creat;
  424.   mystrncpy(session_str,s,sizeof(session_str));
  425.   s=strchr(session_str,'.'); if(s!=NULL) *s=0;
  426.   s=session_str;
  427.   if(*s!=0) {
  428.     int i;
  429.     mkfname(ses_dir_buf,"%s/%s",session_dir,s);
  430.     i=ftest(ses_dir_buf);
  431.     if(i<0) {
  432.       trap_check(s);
  433. /* subsession */
  434.       if(strlen(s)>10 && strchr(s,'_')!=NULL) {
  435.         char *tt;
  436.         tt=strrchr(ses_dir_buf,'_'); if(tt!=NULL) *tt=0;
  437. /* parent session gone. */
  438.         if(ftest(ses_dir_buf)<0) goto creat;
  439.         goto creat2;
  440.       }
  441.       else goto creat;
  442.     }
  443.     if(i!=is_dir) {
  444.       trap_check(s);
  445.       remove_tree(ses_dir_buf); goto creat;
  446.     }
  447.     return;
  448.   }
  449.   creat:
  450.   t=create_job_ident();
  451.   for(i=0;i<MAX_SESRANDOM;i++)
  452.     snprintf(sesrandbuf+strlen(sesrandbuf),
  453.             sizeof(sesrandbuf)-strlen(sesrandbuf),
  454.             "%d,",sesrandomtab[i]);
  455.   sesrandbuf[strlen(sesrandbuf)-1]='\n';
  456.   snprintf(session_str,sizeof(session_str),"%c%c%08lX",
  457.           cars[random()%36],cars[random()%36],t);
  458.   creat2:
  459.   force_setvar(ro_name[ro_session],session_str);
  460.   setsesdir(session_str);
  461. /* check whether the environment is created. */
  462.   s=getvar(ro_name[ro_session]);
  463.   if(s==NULL || strcmp(s,session_str))
  464.     internal_error("cannot_create_session_number");
  465.   snprintf(ses_dir_buf,sizeof(ses_dir_buf)-100,"%s/%s",
  466.           session_dir,session_str);
  467.   if(mkdir(ses_dir_buf,S_IRWXU)==-1)
  468.     internal_error("cannot_create_session_directory");
  469.   mkfname(s2_prefix,"%s/%s",s2_dir,session_str);
  470.   if(mkdir(s2_prefix,S_IRWXU)==-1) mkdirs(s2_prefix);
  471.   mystrncpy(session_prefix,ses_dir_buf,sizeof(session_prefix)); create_pid();
  472.   if(strchr(session_str,'_')==NULL) {
  473.     if((s=getenv("HTTP_REFERER"))!=NULL && *s!=0 && strlen(s)<MAX_FNAME-20
  474.         && strstr(s,"wims")==NULL) {
  475.       char *tt;
  476.       tt=getenv("SERVER_NAME");
  477.       if(tt==NULL || *tt==0 || strstr(s,tt)==NULL)
  478.         set_static_session_var("wims_sreferer",s);
  479.     }
  480.     if(sesrandbuf[0]) set_static_session_var("wims_sesrandom",sesrandbuf);
  481.   }
  482. /* determine http protocol name. How to detect? */
  483.   p=getenv("HTTPS"); if(p!=NULL && strcmp(p,"on")==0) {
  484.       protocol="https"; set_protocol();
  485.   }
  486.   force_setvar("wims_protocol",protocol);
  487.   new_session=1; session_serial=0;
  488.   setvar("wims_new_session","yes");
  489.   if(strchr(session_str,'_')!=NULL) get_static_session_var();
  490.   set_cookie();
  491. }
  492.  
  493. /* Register time of the request. */
  494. void set_req_time(void)
  495. {
  496.   char tstr[64];
  497.  
  498.   snprintf(tstr,sizeof(tstr),"%04d-%02d-%02d.%02d:%02d:%02d=%lu",
  499.          (now->tm_year)+1900, (now->tm_mon)+1, now->tm_mday,
  500.          now->tm_hour, now->tm_min, now->tm_sec, nowtime);
  501.   force_setvar("wims_req_time",tstr);
  502.   if(cmd_type == cmd_new || cmd_type == cmd_renew)
  503.     force_setvar("wims_module_start_time",tstr);
  504.   if(new_session) force_setvar("wims_session_start_time",tstr);
  505. }
  506. /* choose a seed and put in in wims_seed*/
  507. void seed_time(void)
  508. {
  509.   int r; char buf[64];
  510.   struct timeval t;
  511.   gettimeofday(&t,NULL);
  512.   r=t.tv_usec+t.tv_sec*1000;
  513.   if(r<=0) r=1-r;
  514.   snprintf(buf,sizeof(buf),"%d",r);
  515.   force_setvar("wims_seed",buf);
  516. }
  517.  
  518. /* set up module_prefix. */
  519. void set_module_prefix(void)
  520. {
  521.   char tbuf[MAX_FNAME+1], mmbuf[MAX_FNAME+1], *p, *pp, *ps;
  522.   int t,ft;
  523.   struct stat st;
  524.  
  525.   isclassmodule=0;
  526.   p=getvar(ro_name[ro_module]);
  527.   if(p==NULL || *p==0) user_error("no_module_name");
  528. /* security measure: we should not allow users to go back to
  529.  * parent directories.
  530.  */
  531.   if(strstr(p,parent_dir_string)!=NULL) user_error("wrong_module");
  532.   if(strncmp(p,"classes/",strlen("classes/"))==0) isclassmodule=1;
  533.   if(strncmp(p,"devel/",strlen("devel/"))==0) isdevelmodule=1;
  534.   mkfname(module_prefix,"%s/%s",module_dir,p);
  535. /* Now no symbolic link should appear in the module path. */
  536.   mkfname(tbuf,"modules/%s",p);
  537.   for(t=0,ps=pp=strchr(tbuf+strlen("modules/"),'/'); pp;
  538.   *pp='/', ps=pp, pp=strchr(pp+1,'/'), t++) {
  539.   *pp=0; if(lstat(tbuf,&st)) user_error("wrong_module");
  540.   if(t>0 && S_ISLNK(st.st_mode)) {
  541.     if(strcmp(ps,"/local")!=0 ||
  542.           strncmp(tbuf,"modules/home",strlen("modules/home"))==0)
  543.       user_error("wrong_module");
  544.     }
  545.   }
  546. /* Check validity of the module. */
  547.   mkfname(tbuf,"%s/%s",module_prefix,html_file);
  548.   ft=stat(tbuf,&st);
  549.   if(ft!=0 && p[strlen(p)-3]!='.') {
  550.     int i,j;
  551.     char *l;
  552.     l=getvar(ro_name[ro_lang]);
  553.     j=available_lang_no;
  554.     for(i=-1;i<j && ft!=0;i++) {
  555.       if(i<0) mkfname(mmbuf,"%s.%s",p,l);
  556.       else mkfname(mmbuf,"%s.%s",p,available_lang[i]);
  557.       mkfname(module_prefix,"%s/%s",module_dir,mmbuf);
  558.       mkfname(tbuf,"%s/%s",module_prefix,html_file);
  559.       ft=stat(tbuf,&st);
  560.     }
  561.     if(ft==0) force_setvar(ro_name[ro_module],mmbuf);
  562.   }
  563.   if(ft!=0 && !isclassmodule) user_error("wrong_module");
  564.   setenv("module_dir",module_prefix,1); setvar("module_dir",module_prefix);
  565.   module_index();
  566. }
  567.  
  568. /* set up session_prefix. */
  569. int set_session_prefix(void)
  570. {
  571.   char *p, s[32];
  572.  
  573.   if(robot_access) {
  574.     mystrncpy(session_prefix,robot_session,sizeof(session_prefix));
  575.     mystrncpy(s2_prefix,robot_session,sizeof(session_prefix));
  576.     return 0;
  577.   }
  578.   p=getvar(ro_name[ro_session]);
  579.   if(p==NULL || *p==0) user_error("no_session");
  580. /* same reason as for modules */
  581.   if (strchr(p,'/')!=NULL || strstr(p,parent_dir_string)!=NULL
  582.      || *find_word_end(p)!=0) user_error("wrong_session");
  583.   mystrncpy(s,p,sizeof(s));
  584.   p=strchr(s,'.'); if(p!=NULL) *p=0;
  585.   mkfname(session_prefix,"%s/%s",session_dir,s);
  586.   p=strstr(session_prefix,"_mhelp"); if(p!=NULL) *p=0;
  587.   if(ftest(session_prefix)!=is_dir) return -1;
  588.   mkfname(s2_prefix,"%s/%s",s2_dir,s);
  589.   setenv("session_dir",session_prefix,1);
  590.   setenv("s2_dir",s2_prefix,1);
  591.   if(ftest(mkfname(NULL,"%s/.trap",s2_prefix))==is_file)
  592.       user_error("trapped");
  593.   return 0;
  594. }
  595.  
  596. /* check reserved name values in query_string */
  597. void parse_ro_names(void)
  598. {
  599.   int i;
  600.   char *cmd, *p;
  601.   char sesbuf[64];
  602.   create:
  603.   cmd=getvar(ro_name[ro_cmd]);
  604.   if(cmd==NULL || *cmd==0) user_error("no_command");
  605.   for(i=0;i<CMD_NO;i++) if(strcmp(cmd,commands[i])==0) break;
  606.   if(i>=CMD_NO) user_error("bad_command");
  607.   cmd_type=i;
  608.   if(cmd_type == cmd_new) {
  609.     create_session();
  610.     if(set_session_prefix()==0) {
  611.       check_session();
  612.       set_module_prefix();
  613.     }
  614.     else goto redo;
  615.   }
  616.   if (set_session_prefix()==-1 || (cmd_type != cmd_new && check_session())) {
  617.     redo:
  618.     force_setvar(ro_name[ro_cmd],commands[cmd_new]);
  619.     if(strcmp(ro_name[ro_module],home_module)!=0) user_var_no=0;
  620.      goto create;
  621.   }
  622.   if(!new_session) create_pid();
  623.   session_serial++;
  624.   if(robot_access) session_serial=1;
  625.   snprintf(sesbuf,sizeof(sesbuf),"%d",session_serial);
  626.   force_setvar("wims_session_serial",sesbuf);
  627.   p=getvar(ro_name[ro_session]);
  628.   if(p==NULL || *p==0) internal_error("parse_ro_names(): bad session.\n");
  629.   mystrncpy(sesbuf,p,sizeof(sesbuf));
  630.   p=strchr(sesbuf+5,'.');
  631.   if(p!=NULL) *p=0;
  632.   mktmpdir(sesbuf);
  633.   if(!robot_access) {
  634.     setsesdir(sesbuf);
  635.     p=strchr(sesbuf,'_');
  636.     if(p!=NULL) force_setvar("wims_subsession",p);
  637.   }
  638.   snprintf(sesbuf+strlen(sesbuf),sizeof(sesbuf)-strlen(sesbuf),
  639.           ".%d",session_serial);
  640.   force_setvar(ro_name[ro_session],sesbuf);
  641.   if(cmd_type != cmd_new) set_module_prefix();
  642.   set_req_time();
  643.   if(robot_access) check_load(0);
  644.   else {
  645.     if(new_session) auth();
  646.     else {
  647.       p=getvar("wims_user"); if(p==NULL || *p==0) check_load(2);
  648.     }
  649.   }
  650.   if(cmd_type==cmd_help && open_working_file(&m_file,module_about_file)==0)
  651.     var_proc(NULL,0);
  652. }
  653.  
  654.  
  655. /* returns positive or 0 if var_def found, otherwise returns -1. */
  656. int var_def_check(char *name)
  657. {
  658.   char *p, nbuf[MAX_NAMELEN+1];
  659.   int i,tt;
  660.  
  661.   tt=-1;
  662.   for(p=name+strlen(name);p>name && myisdigit(*(p-1));p--)
  663.   ;
  664.   if(*p && *p!='0' && p>name) tt=atoi(p);
  665.   else p=name+strlen(name);
  666.   if(p>name+MAX_NAMELEN) p=name+MAX_NAMELEN;
  667.   memmove(nbuf,name,p-name); nbuf[p-name]=0;
  668.   i=search_list(var_def,defined_var_total,sizeof(var_def[0]),nbuf);
  669.   if(i<0) return -1;
  670.   while(i>0 && tt<var_def[i].beg && strcmp(nbuf,var_def[i-1].name)==0) i--;
  671.   while(i<defined_var_total-1 && tt>var_def[i].end &&
  672.            strcmp(nbuf,var_def[i+1].name)==0) i++;
  673.   if(tt<var_def[i].beg || tt>var_def[i].end) return -1;
  674.   return i;
  675. }
  676.  
  677. int var_def_name(char *n, int v)
  678. {
  679.   char *q, *r;
  680.   int j;
  681.   if(strlen(n)>=MAX_NAMELEN) module_error("defn_too_long");
  682.   var_def[v].name=n;
  683.   if((strncmp(n,wims_prefix,wpflen)==0 &&
  684.         (strncmp(n,"wims_priv_",strlen("wims_priv_"))==0 ||
  685.         search_list(internal_name,INTERNAL_NAME_NO,
  686.                sizeof(internal_name[0]),n+wpflen)>=0)) ||
  687.           search_list(ro_name,RO_NAME_NO,sizeof(ro_name[0]),n)>=0) {
  688.     setvar("wims_reserved_name",n);
  689.     module_error("name_is_reserved");
  690.   }
  691.   for(q=n;myisalnum(*q) || *q=='_'; q++);
  692.   if(q==n) {
  693.     illegal: setvar("wims_bad_name",n);
  694.     module_error("illegal_name");
  695.   }
  696.  
  697.   if(*q=='[') {
  698.     *q++=0; r=find_matching(q,']');
  699.     if(r==NULL) goto illegal;
  700.     *r=0; int i;
  701.     for(i=0;i<special_name_no && strcmp(q, special_name[i].name)!=0; i++);
  702.     if(i<special_name_no) j=special_name[i].value; else j=atoi(q);
  703.     if(j<1) j=1;
  704.     if(j>MAX_VAR_NUM) j=MAX_VAR_NUM;
  705.     var_def[v].beg=1; var_def[v].end=j;
  706.     return j;
  707.   }
  708.   if(*q) goto illegal;
  709.   for(r=q; r>n && myisdigit(*(r-1)); r--);
  710.   if(*r && *r!='0' && r>n) {
  711.     var_def[v].beg=var_def[v].end=atoi(r); *r=0;
  712.   }
  713.   else var_def[v].beg=var_def[v].end=-1;
  714.   return 1;
  715. }
  716.  
  717. int var_def_allow(char *p, int v)
  718. {
  719.   int i;
  720.   for(i=0;i<VAR_ALLOW_NO && strcasecmp(p,var_allow[i])!=0; i++);
  721.   if(i>=VAR_ALLOW_NO) module_error("bad_allow");
  722.   else var_def[v].allow=i;
  723.   return i;
  724. }
  725.  
  726. int varsort(const void *p1, const void *p2)
  727. {
  728.   int i; const struct VAR_DEF *pp1, *pp2;
  729.   pp1=p1; pp2=p2; i=strcmp(pp1->name,pp2->name);
  730.   if(i) return i; else return pp1->end - pp2->end;
  731. }
  732.  
  733. /* parse module's variable definitions */
  734. void get_var_defs(void)
  735. {
  736.   int i, j, k, v, add;
  737.   char *p, *p1, *wlist[MAX_VAR_NUM];
  738.  
  739.   defined_var_total=0;
  740.   if(read_module_file(var_def_file)!=0) return;
  741.   var_def_buf=m_file.textbuf;
  742.   for(m_file.l=v=add=0;v<MAX_VAR_NUM && m_file.l<m_file.linecnt;m_file.l++) {
  743.     if(m_file.lines[m_file.l].isstart!=1) continue;
  744.     p=find_word_start(m_file.lines[m_file.l].address);
  745.     if(*p==0 || *p==comment_prefix_char) continue;  /* empty or comment lines */
  746.     items2words(p);
  747.     if((p1=strchr(p,':'))!=NULL) {  /* new format */
  748.       *p1=' '; i=cutwords(p,wlist,MAX_VAR_NUM); if(i<=1) continue;
  749.       k=var_def_allow(wlist[0],v);
  750.       for(j=1;j<i && v<MAX_VAR_NUM;j++) {
  751.         add+=var_def_name(wlist[j],v); var_def[v].allow=k;
  752.         v++;
  753.       }
  754.     }
  755.     else {
  756.       i=cutwords(p,wlist,3); if(i<2) module_error("too_few_columns");
  757.       add+=var_def_name(wlist[0],v);
  758.       var_def_allow(wlist[1],v);
  759.       var_def[v].defined_in_parm=0;
  760.       v++;
  761.     }
  762.   }
  763.   for(j=0;j<INTERNALDEF_NAME_NO;j++) {
  764.     add+=var_def_name(internaldef_name[j].name,v);
  765.     var_def[v].allow=internaldef_name[j].stat;
  766.     v++;
  767.   }
  768.  
  769.   if(v>=MAX_VAR_NUM) module_error("too_many_variables");
  770.   defined_var_total=v;
  771.   qsort(var_def,v,sizeof(var_def[0]),varsort);
  772.   p=getvar(ro_name[ro_module]);
  773.   if(p==NULL || strncmp(p,"devel/",6)!=0) return;
  774.   for(v=1;v<defined_var_total;v++) {
  775.     if(strcmp(var_def[v].name,var_def[v-1].name)==0 &&
  776.         var_def[v].beg<=var_def[v-1].end) {
  777.       for(j=0;j<INTERNALDEF_NAME_NO;j++) {
  778.         if(strcmp(internaldef_name[j].name,var_def[v-1].name)==0){
  779.           setvar("wims_reserved_name",internaldef_name[j].name);
  780.           module_error("name_is_reserved");
  781.         }
  782.       }
  783.       setvar("wims_bad_name",var_def[v].name);
  784.       module_error("multiple_declaration");
  785.     }
  786.   }
  787. }
  788.  
  789. /* returns 1 if hacked, else 0. */
  790. int try_hack(char *var)
  791. {
  792.   int i, al;
  793.   char vbuf[16];
  794.   i=var_def_check(var);
  795.   if(i<0) return 0;
  796.   al=var_def[i].allow;
  797.   if(al != var_allow_any) switch(cmd_type) {
  798.     case cmd_new:
  799.     case cmd_renew: {
  800.       if (al != var_allow_init && al != var_allow_config) return 0;
  801.       else break;
  802.     }
  803.     case cmd_config: {
  804.       if(al != var_allow_config) return 0;
  805.       else break;
  806.     }
  807.     case cmd_reply: {
  808.       if(al != var_allow_reply) return 0;
  809.       else break;
  810.     }
  811.     case cmd_help: {
  812.       if(al != var_allow_help) return 0;
  813.       else break;
  814.     }
  815.     default: return 0;
  816.   }
  817.   snprintf(vbuf,sizeof(vbuf),"%d",(int) irand(21));
  818.   var_hacking=1; setvar(var,vbuf); var_hacking=0;
  819.   return 1;
  820. }
  821.  
  822. /* set environ variables from last session save
  823.  * The session var file starts with variables which should not
  824.  * be restored. Variables which are restored follow a blank line. */
  825. void set_vars_from_session(void)
  826. {
  827.   char lbuf[MAX_LINELEN+1];
  828.   int i;
  829.   char *p;
  830.  
  831.   if(session_var_ready) memmove(&m_file,&svar_file,sizeof(WORKING_FILE));
  832.   else fopen_session_var_file("r");
  833.   /* look for the first blank line. */
  834.   for(i=0;i<m_file.linecnt && (m_file.lines[i].isstart==0 || m_file.lines[i].llen>0);i++);
  835.   for(i++;i<m_file.linecnt && m_file.lines[i].llen==0;i++);
  836.   if(i>=m_file.linecnt) return;
  837.   m_file.linepointer=i;
  838.   if(isdevelmodule && strstr(session_prefix,"_test")==NULL) isdevelmodule=0;
  839.   while(wgetline(lbuf,MAX_LINELEN, &m_file)!=EOF) {
  840.     p=strchr(lbuf,'=');
  841.     if(p==NULL || p<=lbuf || isspace(lbuf[0]) ) {
  842.   /* this time it is corrupted var file */
  843.       call_ssh("cat %s/var >%s/corrupt.var.bak",session_prefix,log_dir);
  844.       internal_error("get_vars_from_session(): corrupt session variable file.");
  845.     }
  846.     *p=0;p++;
  847.     /* Here we suppose that nobody can tamper session variable
  848.      * file, and do not check variable names against module's
  849.      * definition file. Policy under reserve. */
  850.     /* We do not allow override though.
  851.      * Especially because reply variables should
  852.      * be preserved. */
  853.     if(strncmp(lbuf,var_prefix,strlen(var_prefix))!=0)
  854.       setenv(lbuf,p,0);
  855.     else
  856.       if(lbuf[strlen(var_prefix)]!=0 && getvar(lbuf+strlen(var_prefix))==NULL) {
  857.         if(!isdevelmodule || !try_hack(lbuf+strlen(var_prefix))) {
  858.           setvar(lbuf+strlen(var_prefix),p);
  859.         }
  860.       }
  861.   }
  862.   close_working_file(&m_file,0);
  863. }
  864.  
  865. void start_tracefile(void)
  866. {
  867.   int i;
  868.   putc('\n',trace_file);
  869.   for(i=1; i<=2*trace_indent; i++) putc(' ',trace_file);
  870.   fprintf(trace_file,"%s:",m_file.filepath);
  871.   fflush(trace_file);
  872.   trace_indent++;
  873. }
  874.  
  875. void stop_tracefile(void)
  876. {
  877.   trace_indent--;
  878. }
  879.  
  880. /* Initialize environment variables according to module's
  881.  * variable init or calculation file.
  882.  * init is only used when cmd=new or renew.
  883.  * Requires get_var_defs be run first. */
  884. void var_proc(char *fname,int cache)
  885. {
  886.   int  t;
  887.   char *p, tbuf[MAX_LINELEN+1];
  888.  
  889.   if(fname!=NULL && read_module_file(fname)) return;
  890.   if(untrust&6) get_var_privileges();
  891.   if (trace_file) start_tracefile();
  892.   while(m_file.linepointer<m_file.linecnt) {
  893.     if (trace_file) {fprintf(trace_file," %d",m_file.linepointer+1);
  894.       fflush(trace_file);
  895.     }
  896.     t=m_file.lines[m_file.linepointer].isstart;
  897.     if((t&~2)!=1 || m_file.lines[m_file.linepointer].llen==0) {
  898.       m_file.linepointer++; continue;
  899.     }
  900.     wgetline(tbuf,MAX_LINELEN,&m_file); substnest=0;
  901.     p=find_word_start(tbuf); if(*p==0) continue;
  902.     if((t&2)!=0) exec_main(p+1);
  903.     else exec_set(p);
  904.   }
  905.   if (trace_file) stop_tracefile();
  906.   close_working_file(&m_file,cache);
  907. }
  908.  
  909. /* Deposit the content of wims_deposit into a file */
  910. void var_deposit(char *p)
  911. {
  912.   char fn[MAX_FNAME+1];
  913.   int l,fd;
  914.   if(!trusted_module()) return;
  915.   if(deplen>0) l=deplen; else {
  916.     while(isspace(*p)) p++;
  917.     l=strlen(p);
  918.   }
  919.   if(l<=0) return;
  920.   if(l>MAX_DEPOSITLEN) l=MAX_DEPOSITLEN; /* silent truncation, should not occur */
  921.   mkfname(fn,"%s/user-deposit",session_prefix);
  922.   fd=creat(fn,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if(fd==-1) return;
  923.   write(fd,p,l); close(fd);
  924.   snprintf(fn,sizeof(fn),"%u",l); setvar("wims_deposit_len",fn);
  925. }
  926.  
  927. /* Check and set variables passed in query_string */
  928. void set_vars_from_parm(void)
  929. {
  930.   int i,j,al;
  931.   char *s, vbuf[MAX_LINELEN+1];
  932.   if(forceresume) return;
  933.   for(i=0; i<user_var_no; i++) {
  934.     j=var_def_check(user_variable[i].name);
  935.     if(j<0) continue;
  936.     /* check permissions */
  937.     al=var_def[j].allow;
  938.     if(al != var_allow_any) switch(cmd_type) {
  939.       case cmd_new:
  940.       case cmd_renew:
  941.         if (al != var_allow_init && al != var_allow_config) {
  942. violat:        /* setvar(error_data_string,user_variable[i].name);
  943.               user_error("allow_violation"); */
  944.           goto loopend;
  945.         }
  946.       break;
  947.  
  948.       case cmd_config:
  949.       if(al != var_allow_config) goto violat;
  950.       break;
  951.  
  952.       case cmd_reply:
  953.         if(al != var_allow_reply) goto violat;
  954.         break;
  955.  
  956.       case cmd_help:
  957.         if(al != var_allow_help) goto violat;
  958.         break;
  959.  
  960.       default: goto violat;
  961.     }
  962.     var_def[j].defined_in_parm=1;
  963.     if(strcmp(user_variable[i].name,"wims_deposit")==0) {
  964.       var_deposit(user_variable[i].value); continue;
  965.     }
  966.     mystrncpy(vbuf,user_variable[i].value,sizeof(vbuf));
  967.     if(strchr(vbuf,'$')!=NULL) {
  968.       char *p;
  969.       while((p=strchr(vbuf,'$'))!=NULL)
  970.         string_modify(vbuf,p,p+1,"&#36;");
  971.     }
  972.     s=getvar(user_variable[i].name);
  973.     if(s==NULL || *s==0) setvar(user_variable[i].name, vbuf);
  974.     else {  /* concatenate */
  975.       int k;
  976.       k=strlen(s)+strlen(vbuf);
  977.       if(k>=MAX_LINELEN-2) user_error("string_too_long");
  978.       snprintf(tmplbuf,sizeof(tmplbuf),"%s, %s",s,vbuf);
  979.       setvar(user_variable[i].name, tmplbuf);
  980.     }
  981.     loopend: ;
  982.   }
  983. }
  984.  
  985. /* parms to be eliminated from module_init_parm */
  986. /* char *init_elim[]={
  987.     "module","cmd","session","lang","worksheet","wims_access","useropts"
  988. };
  989. #define init_elim_no (sizeof(init_elim)/sizeof(init_elim[0]))
  990. */
  991.  
  992. void elim_parm(char *str, char *parm)
  993. {
  994.   char *p1, *p2;
  995.   for(p1=strstr(str,parm);p1!=NULL;p1=strstr(p1+1,parm)) {
  996.     if( (p1>str && *(p1-1)!='&') || *(p1+strlen(parm))!='=')
  997.       continue;
  998.     p2=strchr(p1,'&');
  999.     if(p2==NULL) {
  1000.       if(p1>str) *(p1-1)=0; else *p1=0;
  1001.       return;
  1002.     }
  1003.     ovlstrcpy(p1,p2+1); p1--;
  1004.   }
  1005. }
  1006.  
  1007. /* eliminate technical definitions form parameter string
  1008.  * that is parameters from the list RO_NAMES
  1009.  */
  1010. void prep_init_parm(char rqv[])
  1011. {
  1012.   int i;
  1013.   char *p;
  1014.  
  1015.   for(p=strstr(rqv,"&+"); p!=NULL; p=strstr(++p,"&+"))
  1016.     ovlstrcpy(p+1,p+2);
  1017.   for(i=0;i<RO_NAME_NO;i++) elim_parm(rqv,ro_name[i]);
  1018.   if(strlen(rqv)>=MAX_LINELEN) rqv[0]=0;
  1019.   while(rqv[0]=='&') ovlstrcpy(rqv,rqv+1);
  1020.   while(rqv[0]!=0 && rqv[strlen(rqv)-1]=='&') rqv[strlen(rqv)-1]=0;
  1021. }
  1022.  
  1023. /* retain initializing parameters, for use in user references */
  1024. void set_init_parm(void)
  1025. {
  1026.   char *rq, rqv[MAX_LINELEN*2+2], *u, *sh, *seedr, *exotrymax;
  1027.   char *shname, *dirname;
  1028.   int public_sheet, freework_sheet;
  1029.   int len;
  1030.  
  1031.   if(isexam) return;
  1032.   /* reset sheet number and exo number for a sheet */
  1033.   force_setvar("wims_sheet",""); force_setvar("wims_exo","");
  1034.   /* reset freework number and exo number for a freework */
  1035.   force_setvar("wims_fwnumber",""); force_setvar("wims_fwexo","");
  1036.   rq=getenv("QUERY_STRING");
  1037.   if(rq==NULL || *rq==0) {
  1038.     empty:
  1039.     setvar("module_init_parm",""); return;
  1040.   }
  1041.   if(strlen(rq)>=MAX_LINELEN*2) goto empty;
  1042.   _http2env(rqv,rq); prep_init_parm(rqv);
  1043.   /*XSS PROTECTION see also config.c*/
  1044.   len=strcspn(rqv, "<>'\"\\"); rqv[len]=0;
  1045.   setvar("module_init_parm",rqv); public_sheet=0; freework_sheet=0;
  1046. /* seedrepeat=1 or an integer
  1047.   must be in the url and seedrepeat
  1048.   in the var.def of the module to be used */
  1049.   seedr=getvar("seedrepeat");
  1050.   force_setvar("wims_seed_repeat",seedr);
  1051.   exotrymax=getvar("exotrymax");
  1052.   force_setvar("wims_exotrymax",exotrymax);
  1053. /* now determine the sheet number for user */
  1054.   sh=getvar(ro_name[ro_worksheet]); if(sh==NULL) return;
  1055.   if(*sh=='P') {public_sheet=1; sh++;}  /* for public sheet file is in session */
  1056.   if(*sh=='F') {     /* for freework */
  1057.     freework_sheet=1; sh++;
  1058.     shname="Wfreework";
  1059.     dirname="freeworks";
  1060.   }
  1061.   else {   /* for sheet */
  1062.     shname="sheet";
  1063.     dirname="sheets";
  1064.   }
  1065.   u=getvar("wims_user"); if(u==NULL) u="";
  1066.   if(sh!=NULL && *sh!=0) {
  1067.     char buf[MAX_LINELEN+1],ubuf[32], nbuf[1024], *c, *m;
  1068.     char *p1,*p2,*p3,*p4,*p5;
  1069.     int i,j,sheet;
  1070.     sheet=atoi(sh); if(sheet<=0 || sheet>MAX_SHEETS) return;
  1071.     m=getvar(ro_name[ro_module]);
  1072.     if(m==NULL) internal_error("set_init_parm(): module name disapears.");
  1073.     if(*u==0) public_sheet=1;
  1074.     if(!public_sheet) {
  1075.     /* make filename for data on a freework or a sheet in a class */
  1076.       c=getvar("wims_class"); if(c==NULL) c="";
  1077.       snprintf(nbuf,sizeof(nbuf),"%s/%s/.%s%d",
  1078.                class_dir,dirname,shname,sheet);
  1079.     }
  1080.     else {
  1081.       /* make filename for data in case of a public sheet */
  1082.       char bf[MAX_LINELEN+1];
  1083.       int i;
  1084.       accessfile(bf,"r","%s/.sheets",session_prefix);
  1085.       if(bf[0]==0) return;
  1086.       for(i=1, p1=bf;i<sheet;i++,p1=p2) {
  1087.         p2=strchr(p1,'\n');
  1088.         if(p2!=NULL) *p2++=0; else p2=p1+strlen(p1);
  1089.       }
  1090.       p2=strchr(p1,'\n'); if(p2) *p2=0;
  1091.       snprintf(nbuf,sizeof(nbuf),"bases/sheet/%s.def",p1);
  1092.     }
  1093.     /* now nbuf is the filename for data in any case of ressource
  1094.       (sheet / public_sheet / freework) */
  1095.     if(readfile(nbuf,buf,sizeof(buf))==NULL) return;
  1096.     /* buf is the data of ressources. nbuf no more needed */
  1097.     for(p1=strstr(buf,"&+");p1!=NULL;p1=strstr(++p1,"&+"))    /* delete the &+ in buf */
  1098.       ovlstrcpy(p1+1,p1+2);
  1099.     /* in case of use an exercice of the class instead of a public exercise */
  1100.     if(strncmp(m,"classes/",strlen("classes/"))==0) {
  1101.       m="classes/";
  1102.       for(p1=strstr(buf,":classes/");p1;p1=strstr(p1+1,":classes/")) {
  1103.         if(p1==buf || *(p1-1)=='\n') {
  1104.           p1+=strlen(":classes/");
  1105.           p2=find_word_end(p1); if(p2>p1 && *p2=='\n') ovlstrcpy(p1,p2);
  1106.         }
  1107.       }
  1108.     }
  1109.     snprintf(nbuf,sizeof(nbuf),":%s\n%s\n",m,rqv);  /* rqv : execution parameters for the module ; m is the name of exercise module */
  1110.     p1=strstr(buf,nbuf);
  1111.     /* this loop searches exercise parameters in buf
  1112.       calculate num of the exercise in the ressources (sheet /public_sheet / freework)
  1113.     */
  1114.     while(p1>buf && *(p1-1)!='\n') p1=strstr(p1+1,nbuf);
  1115.     if(p1!=NULL) {
  1116.       p2=strchr(buf,':');
  1117.       while(p2>buf && *(p2-1)!='\n') p2=strchr(p2+1,':');
  1118.       for(i=1;p2!=NULL && p2<p1;i++) {
  1119.         p2=strchr(p2+1,':');
  1120.         while(p2>buf && *(p2-1)!='\n') p2=strchr(p2+1,':');
  1121.       }
  1122.       if(p2==NULL) return; /* error which should not occur */
  1123.       snprintf(ubuf,sizeof(ubuf),"%d",i);
  1124.       /* look for dependency information */
  1125.       /* pas utile pour freework mais ne pose pas de probleme tant que les fichiers .wfreework$i ne contiennent
  1126.        que des record avec moins de 7 lignes (pour ne pas activer la fonction de dependance
  1127.        de score  */
  1128.       for(j=0, p3=strchr(p1+strlen(nbuf),'\n');
  1129.       j<3 && p3 && *(p3+1)!=':';
  1130.       j++, p3=strchr(p3+1,'\n'));
  1131.       if(j>=3 && p3!=NULL && *(p3+1)!=':') {
  1132.         p3++; p4=strchr(p3,'\n');
  1133.         if(p4) {
  1134.           *p4++=0;
  1135.           if(*p4!=':') { /* options */
  1136.             p5=strchr(p4,'\n'); if(p5) *p5=0;
  1137.             force_setvar("wims_exoption",p4);
  1138.           }
  1139.         }
  1140.         p3=find_word_start(p3); strip_trailing_spaces(p3);
  1141. /* non-empty dependency information */
  1142.         if(*p3 && !public_sheet) {
  1143.           exodepOK=depcheck(sh,i,p3);
  1144.           if(!exodepOK) setvar("wims_exodep","pending");
  1145.         }
  1146.       }
  1147.       if(public_sheet) {
  1148.         char bf[32];
  1149.         snprintf(bf,16,"P%s",sh);
  1150.         force_setvar("wims_sheet",bf);
  1151.       }
  1152.       else {
  1153.         if(freework_sheet) {
  1154.           /* if an exo is already registered, user cannot launch the same exercise an other time */
  1155.           snprintf(nbuf,sizeof(nbuf),"%s/log/classes/%s/freeworksdata/%s/work/%s-wimsexo/%s",
  1156.                getvar("wims_home"),getvar("wims_class"),sh,u,ubuf);
  1157.           if(ftest(mkfname(NULL,"%s",nbuf))!=is_file) {
  1158.             force_setvar("wims_fwnumber",sh);
  1159.             force_setvar("wims_fwexo",ubuf);
  1160.           }
  1161.         }
  1162.         else {
  1163.           force_setvar("wims_sheet",sh);
  1164.           force_setvar("wims_exo",ubuf);
  1165.           wims_sheet=sheet; wims_exo=i;
  1166.         }
  1167.       }
  1168.     }
  1169.   }
  1170. }
  1171.  
  1172. /* user with class: whether exercise is registered
  1173.  * Returns 1 if got, 0 otherwise. */
  1174. int get_parmreg(void)
  1175. {
  1176.   char *p, *cl, *u, nbuf[MAX_FNAME+1];
  1177.   struct stat st;
  1178.  
  1179.   u=getvar("wims_user"); cl=getvar("wims_class");
  1180.   if(u==NULL || cl==NULL || *u==0 || *cl==0 || strcmp(u,"supervisor")==0
  1181.        || wims_sheet<=0 || wims_exo<=0) return 0;
  1182.   mkfname(nbuf,"%s/.parmreg/%s.%d.%d", class_dir,u,wims_sheet,wims_exo);
  1183.   p=getvar("wims_scorereg");
  1184.   if(p!=NULL && strcmp(p,"suspend")==0) {
  1185.     unlink(nbuf); return 0;
  1186.   }
  1187.   if(stat(nbuf,&st)) return 0;
  1188.   /* latency is 10 min. */
  1189.   if(st.st_mtime<nowtime-600 || st.st_mtime > nowtime) {
  1190.      unlink(nbuf); return 0;
  1191.   }
  1192.   if(open_working_file(&m_file,nbuf)!=0) return 0;
  1193.   mkfname(m_file.name,"parmreg/%s.%d.%d",u,wims_sheet,wims_exo);
  1194.   while(wgetline(tmplbuf,MAX_LINELEN, &m_file)!=EOF) {
  1195.     p=strchr(tmplbuf,'=');
  1196.     if(p==NULL || p<=tmplbuf || isspace(tmplbuf[0]) )
  1197.       /* this time it is corrupted var file */
  1198.       internal_error("get_parmreg(): corrupt parmreg file.");
  1199.     *p=0;p++;
  1200.     if(strncmp(tmplbuf,var_prefix,strlen(var_prefix))!=0) setenv(tmplbuf,p,1);
  1201.     else if(tmplbuf[strlen(var_prefix)]!=0) force_setvar(tmplbuf+strlen(var_prefix),p);
  1202.   }
  1203.   parm_restore=1;
  1204.   close_working_file(&m_file,0); return 1;
  1205. }
  1206.  
  1207. /* reset seed according to the values of
  1208.   wims_seed_repeat and wims_seed_score
  1209. */
  1210. /* for non registered users or suspended score,
  1211.   save some variables wims_seedcnt and seedlastcnt in sessions/xxx/var
  1212. */
  1213. void reset_seed (void) {
  1214.   char *p, *seedr, buf[64], *sh, *ex, *tseed, *seedcnt, *seedlastcnt;
  1215.   char *mp=getvar("module");
  1216.   sh=getvar("wims_sheet"); ex=getvar("wims_exo");
  1217.   seedr=getvar("wims_seed_repeat");
  1218.   /* number of seeds during the sessions only used for unregistered */
  1219.   seedcnt=getvar("wims_seedcnt");
  1220.   if(seedcnt==NULL || *seedcnt==0) {
  1221.     force_setvar("wims_seedcnt","0");
  1222.     seedcnt=getvar("wims_seedcnt");
  1223.   }
  1224.   /* number of tries with the actual seed only used for unregistered
  1225.     or score suspended */
  1226.   seedlastcnt=getvar("wims_seedlastcnt");
  1227.   if(seedlastcnt==NULL || *seedlastcnt==0) {
  1228.     force_setvar("wims_seedlastcnt","0");
  1229.     seedlastcnt=getvar("wims_seedlastcnt");
  1230.   }
  1231.   if(seedr!=NULL && atoi(seedr)>0) { /* seedrepeat>1 */
  1232.     p=getvar("wims_seed_score");
  1233.     if(evalue(p)>=10){
  1234.       seed_time(); force_setvar("wims_seed_score",NULL);
  1235.       snprintf(buf,sizeof(buf), "%d", atoi(seedcnt)+1);
  1236.       force_setvar("wims_seedcnt",buf);
  1237.       seedcnt=getvar("wims_seedcnt");
  1238.       force_setvar("wims_seedlastcnt","0");
  1239.       seedlastcnt=getvar("wims_seedlastcnt");
  1240.     }
  1241.     else { /* score < 10 */
  1242.       /* is score suspended by the student ? */
  1243.       char *screg=getvar("wims_scorereg");
  1244.       /* is score suspended by the supervisor ? */
  1245.       int scregs=0;
  1246.       if(sh!=NULL && *sh!=0)
  1247.         scregs=getscorestatus(getvar("wims_class"),atoi(sh));
  1248.       if(sh!=NULL && *sh!=0 && ex!=NULL && *ex!=0
  1249.           && (screg==NULL || strcmp(screg,"suspend")!=0)
  1250.           && (scregs!=0)){
  1251.         /* the case of a supervisor looking at the sheet is not treated */
  1252.         tseed=getseedscore(getvar("wims_class"), getvar("wims_user"), atoi(sh), atoi(ex));
  1253.         if( tseed!=0 ) {
  1254.           mystrncpy(buf, tseed,sizeof(buf));
  1255.           force_setvar("wims_seed",buf);
  1256.         }
  1257.         else seed_time();
  1258.       }
  1259.       else { /* non registered or score suspended
  1260.           and seedrepeat>1 and score <10 */
  1261.         if (cmd_type==cmd_new ||cmd_type==cmd_renew) {
  1262.           snprintf(buf,sizeof(buf),"%d",atoi(seedlastcnt)+1);
  1263.           force_setvar("wims_seedlastcnt",buf);
  1264.           seedlastcnt=getvar("wims_seedlastcnt");
  1265.           if(atoi(seedlastcnt) >= atoi(seedr)){
  1266.             seed_time();
  1267.             if(strcmp(mp,home_module)!=0 && cmd_type!=cmd_intro){
  1268.               snprintf(buf,sizeof(buf),"%d",0);
  1269.               force_setvar("wims_seedlastcnt",buf);
  1270.               seedlastcnt=getvar("wims_seedlastcnt");
  1271.               snprintf(buf,sizeof(buf),"%d",atoi(seedcnt)+1);
  1272.               force_setvar("wims_seedcnt",buf);
  1273.               seedcnt=getvar("wims_seedcnt");
  1274.             }
  1275.             else {
  1276.               force_setvar("wims_seedcnt","0");
  1277.               force_setvar("wims_seedlastcnt","0");
  1278.             }
  1279.           }
  1280.         }
  1281.       }
  1282.     }
  1283.   }
  1284.   else {// no seedrepeat
  1285.     seed_time();
  1286.     if (cmd_type==cmd_reply && strcmp(mp,home_module)!=0){
  1287.       snprintf(buf,sizeof(buf),"%d",atoi(seedcnt)+1);
  1288.       force_setvar("wims_seedcnt",buf);
  1289.       seedcnt=getvar("wims_seedcnt");
  1290.       force_setvar("wims_seedlastcnt","0");
  1291.     }
  1292.     else {
  1293.       if (strcmp(mp,home_module)==0 || cmd_type==cmd_intro) {
  1294.         force_setvar("wims_seedcnt","0");
  1295.         force_setvar("wims_seedlastcnt","0");
  1296.       }
  1297.     }
  1298.   }
  1299.   p=getvar("wims_seed");
  1300.   if(p!=NULL && (cmd_type==cmd_new || cmd_type==cmd_renew || cmd_type==cmd_next)){
  1301.     mystrncpy(buf,p,sizeof(buf)); setenv("tmp_seed",buf,1);
  1302.     exec_setseed(buf);
  1303.   }
  1304. }
  1305.  
  1306. /* set environment variables */
  1307. void set_variables(void)
  1308. {
  1309.   outputing=0; readnest=0;
  1310.   get_var_defs();
  1311.   set_vars_from_parm();
  1312.   if(cmd_type != cmd_new && cmd_type != cmd_renew) {
  1313.     set_vars_from_session();
  1314.     if(cmd_type==cmd_next) reset_seed();
  1315.   }
  1316.   else {
  1317.     set_init_parm();
  1318.     reset_seed();
  1319.     if(wims_sheet>0 && get_parmreg()) {
  1320.       cmd_type=cmd_resume; force_setvar("cmd","resume");
  1321.       var_proc(main_var_proc_file,0); return;
  1322.     }
  1323.     checkrafale();
  1324.     var_proc(var_init_file,0);
  1325.   }
  1326. /* check_var_bounds(); */
  1327.   var_proc(main_var_proc_file,0);
  1328. }
  1329.  
  1330. /* Output a phtml file. */
  1331. void phtml_put(char *fname,int cache)
  1332. {
  1333.   int t;
  1334.   char tbuf[MAX_LINELEN+1];
  1335.   char *s;
  1336.   outputing=1;
  1337.      /* File not found; we give empty output, but no error message. */
  1338.   if(fname!=NULL && read_module_file(fname)!=0) return;
  1339.   if(untrust&6) get_var_privileges();
  1340.   if (trace_file) start_tracefile();
  1341.   while(m_file.linepointer<m_file.linecnt) {
  1342.     if (trace_file) {
  1343.       fprintf(trace_file," %d",m_file.linepointer+1);
  1344.       fflush(trace_file);
  1345.     }
  1346.     t=m_file.lines[m_file.linepointer].isstart;
  1347.     if((t&~18)!=1) {m_file.linepointer++; continue;}
  1348.     wgetline(tbuf,MAX_LINELEN,&m_file); substnest=0;
  1349.     if((t&2)!=0) {exec_main(tbuf+1); continue;}
  1350.     substit(tbuf);
  1351.     s=getvar("wims_parm_detag");
  1352.     if(s!=NULL && *s != 0) calc_detag(tbuf);
  1353.     output0(tbuf); _output_("\n");
  1354.   }
  1355.   if (trace_file) stop_tracefile();
  1356.   close_working_file(&m_file,cache);
  1357. }
  1358.  
  1359. /* output a file in base html directory. Internal use only. */
  1360. void phtml_put_base(char *fname,int cache)
  1361. {
  1362.   WORKING_FILE save;
  1363.   char modsave[MAX_FNAME+1];
  1364.   memmove(&save,&m_file,sizeof(WORKING_FILE));
  1365.   mystrncpy(modsave,module_prefix,sizeof(modsave));
  1366.   ovlstrcpy(module_prefix,"html");
  1367.   phtml_put(fname,cache);
  1368.   mystrncpy(module_prefix,modsave,sizeof(module_prefix));
  1369.   memmove(&m_file,&save,sizeof(WORKING_FILE));
  1370. }
  1371.  
  1372. /* Read main.phtml, process it, and write to stdout. */
  1373. void main_phtml_put(char *mname)
  1374. {
  1375.   char *p, buf[1024], txbuf[256], dirnbuf[256], bgbuf[256], spfbuf[256], ebuf[256];
  1376.   char *bcolor, *refcolor, *bg, *tx, *dirn, *vlink, *link, *hlink, *spf ;
  1377.   define_html_header(); readnest=0;
  1378.   nph_header(200);
  1379.   p=getvar("wims_backslash_insmath");
  1380.   if(p!=NULL && strcasecmp(p,"yes")==0) backslash_insmath=1;
  1381.   p=getvar("wims_expire");
  1382.   if(p!=NULL) p=strstr(p,"no-cache");
  1383.   if(p!=NULL) _output_("Cache-Control: no-cache, no-store, must-revalidate\r\n");
  1384. /* expiration date */
  1385.   if(mode==mode_default) {
  1386.     if(!robot_access && (cmd_type!=cmd_intro || p!=NULL)) {
  1387.       char *expir="Sat, 26 Jul 1990 05:00:00 GMT";
  1388.       snprintf(ebuf,sizeof(ebuf),"%s",expir);
  1389.     }
  1390.     else {
  1391. /* expiration in 10 days for robot access or intro page. */
  1392.       time_t t=nowtime+(long) 10*24*3600;
  1393.       { struct tm *tt = localtime(&t);
  1394.         strftime(ebuf,sizeof(ebuf),"%a, %d %b %Y %T GMT", tt);
  1395.       }
  1396.     }
  1397.     strip_trailing_spaces(ebuf);
  1398.     output("Expires:%s\r\n",ebuf);
  1399.   }
  1400.  
  1401.   output("Server: %s %s (%s)\n", SHORTSWNAME,wims_version,LONGSWNAME);
  1402.   if(!robot_access && strcasecmp(usecookie,"yes")==0 && setcookie
  1403.        && mode!=mode_popup) {
  1404.     if(cookieset[0]==0) {
  1405.       p=getvar("wims_sescookie");
  1406.       if(p!=NULL && *p!=0) mystrncpy(cookieset,p,sizeof(cookieset));
  1407.     }
  1408.      output("Set-Cookie: %s%s;SameSite=Strict; path=/\r\n",cookieheader,cookieset);
  1409.   }
  1410.   p=getvar("wims_main_font");
  1411.   if(p!=NULL && *p!=0) output("Content-type: text/html; charset=%s\r\n\r\n",p);
  1412.   else _output_("Content-type: text/html\r\n\r\n");
  1413.  
  1414.   bcolor=getvar("wims_bgcolor");
  1415.   if(bcolor==NULL || *bcolor==0) bcolor=bgcolor;
  1416.  
  1417.   link=getvar("wims_link_color");
  1418.   if(link==NULL || *link==0) link="blue";
  1419.  
  1420.   vlink=getvar("wims_vlink_color");
  1421.   if(vlink==NULL || *vlink==0) vlink="blue";
  1422.  
  1423.   hlink=getvar("wims_hlink_color");
  1424.   if(hlink==NULL || *hlink==0) vlink="red";
  1425.  
  1426.   refcolor=getvar("wims_ref_bgcolor");
  1427.   if(refcolor==NULL || *refcolor==0) {
  1428.     setvar("wims_ref_bgcolor","white");
  1429.     refcolor="white";
  1430.   }
  1431.  
  1432.   bg=getvar("wims_bgimg"); bgbuf[0]=0;
  1433.   if(bg!=NULL && *bg!=0 && strchr(bg,'\"')==NULL) {
  1434.     if(strchr(bg,'/')==NULL)
  1435.       snprintf(bgbuf,sizeof(bgbuf),"background-image: url(\"gifs/bg/%s\");",bg);
  1436.      else
  1437.       snprintf(bgbuf,sizeof(bgbuf),"background-image: url(\"%s\");",bg);
  1438.   }
  1439.   setvar("wims_bodyimg",bgbuf);
  1440.   tx=getvar("wims_textcolor");
  1441.   if(tx!=NULL && *tx!=0 && strchr(tx,'\"')==NULL) {
  1442.     snprintf(txbuf,sizeof(txbuf),"color:%s;",tx);
  1443.   }
  1444.   else txbuf[0]=0;
  1445.    /* special fonts defined in special_font -should also take the value specialfont in wims.conf */
  1446.   if(spec_font==1){
  1447.     spf=getvar("wims_specialfont");
  1448.     if(spf!=NULL && *spf!=0) { snprintf(spfbuf,sizeof(spfbuf),"%s",spf);}
  1449.     else { snprintf(spfbuf,sizeof(spfbuf),"%s",special_font); }
  1450.     setvar("wims_special_font",spfbuf);
  1451.   }
  1452.   dirn=getvar("wims_main_dirn"); /* "rtl" for arabic writing ; on pourrait laisser vide pour les autres ? */
  1453.   if(dirn!=NULL && *dirn!=0 && strchr(dirn,'\"')==NULL) {
  1454.     snprintf(dirnbuf,sizeof(dirnbuf),"dir=\"%s\"",dirn);
  1455.   }
  1456.   else dirnbuf[0]=0;
  1457.   if(mode==mode_popup) {
  1458.     snprintf(buf,sizeof(buf), "class=\"main_body mode_popup\" %s", dirnbuf);
  1459.   }else{
  1460.     snprintf(buf,sizeof(buf), "class=\"main_body\" %s",dirnbuf);
  1461.   }
  1462.   setvar("wims_htmlbody",buf);
  1463.   phtml_put(mname,0);
  1464. }
  1465.  
  1466. void _write_var(char *name, FILE *varf,int user,int skip)
  1467. {
  1468.   char *s, buf[MAX_NAMELEN+9], nbf[MAX_NAMELEN+9];
  1469.  
  1470.   if((user&2)!=0) {
  1471.     snprintf(nbf,sizeof(nbf),"%s%s",wims_prefix,name); name=nbf;
  1472.   }
  1473.   if((user&1)!=0) {
  1474.     snprintf(buf,sizeof(buf),"%s%s",var_prefix,name); s=_getvar(name);
  1475.   }
  1476.   else {
  1477.     mystrncpy(buf,name,sizeof(buf)); s=getenv(name);
  1478.   }
  1479.   if(s==NULL) s="";
  1480.   if(skip && *s==0) return;
  1481.   fprintf(varf,"%s=",buf);
  1482.   if(strchr(s,'\n')==NULL) fputs(s,varf);
  1483.   else
  1484.     while(*s) {
  1485.       if(*s=='\n') fputc('\\',varf);
  1486.        fputc(*s,varf); s++;
  1487.     }
  1488.   fputc('\n',varf);
  1489. }
  1490.  
  1491. void _write_vars(FILE *varf)
  1492. {
  1493.   int i,j,k;
  1494.   char nbuf[MAX_NAMELEN+1];
  1495.   for(i=0;i<defined_var_total;i++) {
  1496.     if(var_def[i].beg>=0) {
  1497.       if(var_def[i].end<=var_def[i].beg) {
  1498.         snprintf(nbuf,sizeof(nbuf),"%s%d",var_def[i].name,var_def[i].beg);
  1499.         _write_var(nbuf,varf,1,1);
  1500.       }
  1501.       else {
  1502.         char *pbuf[MAX_VAR_NUM];
  1503.         j=varsuite(var_def[i].name,var_def[i].beg,var_def[i].end,pbuf,MAX_VAR_NUM);
  1504.         for(k=0;k<j;k++) _write_var(pbuf[k],varf,1,1);
  1505.       }
  1506.     }
  1507.     else _write_var(var_def[i].name,varf,1,1);
  1508.   }
  1509. }
  1510.  
  1511. /* save exercise parm for registered users */
  1512. void save_parmreg(void)
  1513. {
  1514.   char *p, *u, *sh, *ex, nbuf[MAX_FNAME+1], dbuf[MAX_FNAME+1];
  1515.   int s;
  1516.   FILE *varf;
  1517.  
  1518.   if(cmd_type!=cmd_reply && cmd_type!=cmd_new && cmd_type!=cmd_renew)
  1519.     return;
  1520.   u=getvar("wims_user");
  1521.   if(class_dir[0]==0 || *u==0) return;
  1522.   sh=getvar("wims_sheet"); ex=getvar("wims_exo");
  1523.   if(sh==NULL || ex==NULL || *sh==0 || *ex==0) return;
  1524.   mkfname(nbuf,"%s/.parmreg/%s.%s.%s", class_dir,u,sh,ex);
  1525.   if(cmd_type==cmd_reply) {
  1526.     unlink(nbuf); return;
  1527.   }
  1528.   p=getvar("wims_scorereg");
  1529.   if(p!=NULL && strcmp(p,"suspend")==0) return;
  1530. /* these two lines must be before random factor
  1531.  * in order to set variable wims_scoring */
  1532.   s=atoi(sh); if(getscorestatus(getvar("wims_class"),s)==0) return;
  1533.   if(strcmp(u,"supervisor")==0) return;
  1534. /* 0.2 is random factor to trigger exercise parm register */
  1535. /*    return;*/
  1536.  // if((double) random()<(double) RAND_MAX*0.2){ }
  1537.   return;
  1538.   mkfname(dbuf,"%s/.parmreg",class_dir);
  1539.   mkdirs(dbuf); varf=fopen(nbuf,"w"); if(varf==NULL) return;
  1540.   _write_var("module_init_parm",varf,1,0);
  1541.   _write_var("wims_sheet",varf,1,1);
  1542.   _write_var("wims_exo",varf,1,1);
  1543.   _write_var("wims_scoring",varf,1,1);
  1544.   _write_var("wims_seed",varf,1,1);
  1545.   _write_vars(varf);
  1546.   fclose(varf);
  1547. }
  1548.  
  1549. void exolog(char *fname)
  1550. {
  1551.   FILE *varf, *varg;
  1552.   int c;
  1553.   char logftmp[MAX_FNAME+1], *sess;
  1554.  
  1555. /* add by FG to put w_module_score at the top of the file */
  1556.   if ((getenv("w_module_score"))!=NULL )
  1557.   {
  1558.     sess=getvar("wims_session");
  1559.     mkfname(logftmp,"%s/%s/.tmp%lu",s2_dir,sess,nowtime);
  1560.     rename(fname,logftmp);
  1561.     varf=fopen(fname,"a");
  1562.     if(varf!=NULL) {
  1563.       _write_var("module_score",varf,1,1);
  1564.       varg=fopen(logftmp,"r");
  1565.       if(varg!=NULL) {
  1566.         while ( (c=getc (varg)) != EOF) putc(c,varf);
  1567.         fclose(varg);
  1568.         }
  1569.         fclose(varf);
  1570.         remove(logftmp);
  1571.      }
  1572.   }
  1573. /* end of add */
  1574.   varf=fopen(fname,"a");
  1575.   if(varf!=NULL) {
  1576. /* The first 4 lines should not be modified */
  1577.     fprintf(varf,"\n:\n");
  1578.     _write_var("QUERY_STRING",varf,0,0);
  1579.     _write_var("module",varf,1,0);
  1580.     _write_var("cmd",varf,1,0);
  1581.     _write_var("module_init_parm",varf,1,0);
  1582.     _write_var("wims_scoring",varf,1,1);
  1583.     _write_var("module_score",varf,1,1);
  1584.     fprintf(varf,"w_wims_checktime1=%lu\n\
  1585. w_wims_checktime2=%s\n",nowtime,nowstr);
  1586.     _write_var("wims_seed",varf,1,1);
  1587.     _write_vars(varf);
  1588.     fclose(varf);
  1589.   }
  1590. }
  1591.  
  1592. /* save variables to session var file */
  1593. void save_session_vars(void)
  1594. {
  1595.   int i;
  1596.   char *mp, *sh, *ex, *ll;
  1597.   FILE *varf;
  1598. /* light pages don't need saved variables. ? */
  1599. /*    if(varchr(module_prefix,"light")!=NULL) return;*/
  1600.   if(robot_access) return;
  1601. /* no variable saving if cmd=help? */
  1602.   if(cmd_type==cmd_help) return;
  1603.   lastdatafile[0]=lastftest[0]=0;
  1604.   lessrafale();
  1605.   mp=getvar("wims_nextmodule");
  1606.   if(mp!=NULL && *mp!=0) {
  1607.     mp=getvar("module");
  1608.     if(strcmp(mp,home_module)==0)
  1609.       force_setvar("module",getvar("wims_nextmodule"));
  1610.   }
  1611.   varf=fopen_session_var_file("w");
  1612.   for(i=0;i<HEADER_VAR_NO;i++) _write_var(header_var_name[i],varf,0,0);
  1613.   for(i=0;i<RO_NAME_NO;i++) _write_var(ro_name[i],varf,1,0);
  1614.   for(i=0;i<INTERNAL_NAME_NO;i++) {
  1615.     if(internal_name[i].stat==0)
  1616.       _write_var(internal_name[i].name,varf,3,0);
  1617.   }
  1618.   _write_var("password",varf,0,1);
  1619.   save_parmreg();
  1620.   if(new_session) fprintf(varf,"wims_new_session=yes\n");
  1621.   fprintf(varf,"\n");
  1622.   _write_var("module_init_parm",varf,1,0);
  1623.   _write_var("wims_sheet",varf,1,1);
  1624.   _write_var("wims_exo",varf,1,1);
  1625.   _write_var("wims_scoring",varf,1,1);
  1626.   _write_vars(varf);
  1627.   fclose(varf);
  1628.   if(cmd_type==cmd_new || cmd_type==cmd_renew || cmd_type==cmd_reply || cmd_type==cmd_next) {
  1629.     ll=getvar("wims_class_examlog");
  1630.     if(ll!=NULL && *ll!=0) i=atoi(ll); else i=examlog_limit;
  1631.     if(strstr(session_prefix,"_exam")!=NULL && examlogf[0]!=0 &&
  1632.         simuxam==0 && i>0) {
  1633.       mkdirs(examlogd); exolog(examlogf);
  1634.     }
  1635.     else {
  1636.       ll=getvar("wims_class_exolog");
  1637.       sh=getvar("wims_sheet"); ex=getvar("wims_exo");
  1638.       if(ll!=NULL && atoi(ll)>0) {
  1639.         char buf[MAX_FNAME+1];
  1640.         if(sh!=NULL && *sh!=0 && ex!=NULL && *ex!=0){
  1641.           mkfname(buf,"%s/exolog.%s.%s",session_prefix,sh,ex);
  1642.         }
  1643.         else { mkfname(buf,"%s/exolog",session_prefix);}
  1644.         if(cmd_type==cmd_new || cmd_type==cmd_renew) unlink(buf);
  1645.         exolog(buf);
  1646.       }
  1647.       /* for auto log of exercise in freework */
  1648.       if(freeworklogf[0]!=0) {
  1649.         char buf[MAX_FNAME+1],*sess,c;
  1650.         FILE *varg;
  1651.         mkdirs(freeworklogd);
  1652.         sess=getvar("wims_session");
  1653.         mkfname(buf,"%s/%s/exolog",session_dir,sess);
  1654.         varg=fopen(buf,"r");
  1655.         if(varg!=NULL) {
  1656.           varf=fopen(freeworklogf,"w");
  1657.           while ( (c=getc (varg)) != EOF)
  1658.             putc (c,varf);
  1659.           fclose(varg);
  1660.           fclose(varf);
  1661.         }
  1662.       }
  1663.     }
  1664.   }
  1665.   if(var_def_buf) free(var_def_buf);
  1666. }
  1667.