Subversion Repositories wimsdev

Rev

Rev 1160 | Go to most recent revision | 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. char *computed_var_start; /* pointer to read-in var def file */
  20. int session_var_ready=0;
  21. char last_host[32]="";
  22. char *robotcheck="";
  23.  
  24. char *header_var_name[]={
  25.     "REMOTE_ADDR", "HTTP_REFERER", "QUERY_STRING", "HTTP_USER_AGENT",
  26.      "HTTP_COOKIE"
  27. };
  28. #define HEADER_VAR_NO (sizeof(header_var_name)/sizeof(header_var_name[0]))
  29.  
  30. char *var_allow[]={
  31.     "deny" , "init" , "config" ,
  32.       "reply", "any", "help"
  33. };
  34. enum {
  35.     var_allow_deny, var_allow_init, var_allow_config,
  36.       var_allow_reply, var_allow_any, var_allow_help
  37. } VAR_ALLOWS;
  38. #define VAR_ALLOW_NO (sizeof(var_allow)/sizeof(var_allow[0]))
  39.  
  40.         /* install a temporary directory for the session */
  41. void mktmpdir(char *p)
  42. {
  43.     char *base;
  44.     if(p==NULL || *p==0 || strstr(p,"robot")!=NULL) return;
  45.     if(strstr(tmp_dir,"sessions")!=NULL) return;
  46.     if(ftest("../chroot/tmp/sessions/.chroot")==is_file) base="chroot/tmp";
  47.     else base="tmp";
  48.     mkfname(tmp_dir,"../%s/sessions/%s",base,p);
  49.     remove_tree(tmp_dir); mkdirs(tmp_dir);
  50.     chmod(tmp_dir,S_IRUSR|S_IWUSR|S_IXUSR
  51.           |S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
  52.     setenv("tmp_dir",tmp_dir,1); setenv("TMPDIR",tmp_dir,1);
  53. }
  54.  
  55.         /* Open session variable file */
  56. FILE *fopen_session_var_file(char read_or_write[])
  57. {
  58.     char *nbuf; FILE *f;
  59.  
  60.     nbuf=mkfname(NULL,"%s/var",session_prefix);
  61.     if(read_or_write[0]=='r') {
  62.         if(open_working_file(&m_file,nbuf)!=0) return NULL;
  63.         mkfname(m_file.name,"session_var");
  64.         return stdin;
  65.     }
  66.     f=fopen(nbuf,read_or_write);
  67.     if(f==NULL) {
  68.           /* expired_session */
  69.         internal_error("fopen_session_var_file(): unable to create session variable file.");
  70.     }
  71.     mkfname(m_file.name,"session_var");
  72.     m_file.l=0;
  73.     return f;
  74. }
  75.  
  76.         /* Open a module file, read only, with name checking.
  77.          * returns NULL if error. */
  78. int read_module_file(char *fname)
  79. {
  80.     char nbuf[MAX_FNAME+1];
  81.  
  82.     if(get_cached_file(fname)>=0) return 0;
  83.     if(find_module_file(fname,nbuf,0)) return -1;
  84.     if(open_working_file(&m_file,nbuf)!=0) return -1;
  85.     untrust|=(untrust>>8);
  86.     mystrncpy(m_file.name,fname,sizeof(m_file.name));
  87.     if(strncmp(module_prefix,module_dir,strlen(module_dir))!=0) m_file.nocache|=8;
  88.     return 0;
  89. }
  90.  
  91. int varget[]={ro_module,ro_lang,ro_useropts,ro_worksheet};
  92. #define varget_no (sizeof(varget)/sizeof(varget[0]))
  93.  
  94.         /* set up ref strings according to protocol */
  95. void set_protocol(void)
  96. {
  97.     if(strcmp(protocol,"https")!=0) return;
  98.     if(strncmp(ref_name,"http:",5)==0) {
  99.         string_modify(ref_name,ref_name+4,ref_name+4,"s");
  100.         string_modify(ref_base,ref_base+4,ref_base+4,"s");
  101.         force_setvar("wims_ref_name",ref_name);
  102.     }
  103. }
  104.  
  105.         /* verify class participant connection data */
  106. void classlock(void)
  107. {
  108.     int lvl;
  109.     char *p;
  110.    
  111.     p=getvar("wims_classlock"); if(p==NULL) lvl=0; else {
  112.         p=find_word_start(p);
  113.         lvl=*p-'0'; if(lvl<0 || lvl>7) lvl=0;
  114.     }
  115.     if(lvl==7) {        /* closed */
  116.         p=getvar("wims_user");
  117.         if(p==NULL || strcmp(p,"supervisor")!=0) user_error("class_closed");
  118.     }
  119.     if(lvl==2 || lvl==4 || lvl==6) {    /* https */
  120.         p=getenv("HTTPS");
  121.         if(p==NULL || strcasecmp(p,"on")!=0) user_error("need_https");
  122.     }
  123.     if(lvl==3 || lvl>=5) {
  124.         if(strcmp(last_host,remote_addr)!=0) user_error("bad_host");
  125.     }
  126.     if((lvl==1 || lvl>=4) && cookiegot[0]==0) { /* cookie */
  127.         setcookie=1;
  128.         setvar("cookie_module",getvar(ro_name[ro_module]));
  129.         setvar("cookie_cmd",getvar(ro_name[ro_cmd]));
  130.         force_setvar(ro_name[ro_module],home_module);
  131.         force_setvar(ro_name[ro_cmd],commands[cmd_new]);
  132.         setvar("wims_askcookie","yes");
  133.         return;
  134.     }
  135.     else setcookie=0;
  136. }
  137.  
  138.         /* get static session variables */
  139. void get_static_session_var(void)
  140. {
  141.     char *p, *pe, *p2, *p3;
  142.     char sbuf[MAX_FNAME+1], tbuf[MAX_LINELEN+1];
  143.     mystrncpy(sbuf,session_prefix,sizeof(sbuf));
  144.     for(p=sbuf+strlen(sbuf);p>sbuf && *p!='_' && *p!='/'; p--);
  145.     if(p>sbuf && *p=='_') *p=0;
  146.     accessfile(tbuf,"r","%s/var.stat",sbuf);
  147.     p=strrchr(sbuf,'/'); if(p!=NULL) p++; else p=sbuf;
  148.     mktmpdir(p);
  149.     for(p=find_word_start(tbuf);*p;p=find_word_start(pe)) {
  150.         pe=strchr(p,'\n'); if(pe!=NULL) *pe++=0; else pe=p+strlen(p);
  151.         p2=strchr(p,'='); if(p2==NULL) continue;
  152.         *p2++=0; force_setvar(p,p2);
  153.     }
  154.     p=getvar("wims_class"); if(p==NULL || *p==0) return;
  155.     mkfname(class_dir,"%s/%s",class_base,p);
  156.     classlock();
  157.     p3=getvar("wims_class_refcolor"); if(p3!=NULL && *p3!=0)
  158.       force_setvar("wims_ref_bgcolor",p3);
  159.     p2=getvar(ro_name[ro_module]);
  160.     if(p2==NULL || strncmp(p2,"classes/",strlen("classes/"))!=0) return;
  161.     mkfname(sbuf,"classes/%s",lang);
  162.     if(strcmp(sbuf,p2)!=0) force_setvar(ro_name[ro_module],sbuf);
  163. }
  164.  
  165.         /* set one static session variable */
  166. void set_static_session_var(char *name, char *val)
  167. {
  168.     char *p;
  169.     char sbuf[MAX_FNAME+1], tbuf[MAX_LINELEN+1];
  170.     mystrncpy(sbuf,session_prefix,sizeof(sbuf));
  171.     for(p=sbuf+strlen(sbuf);p>sbuf && *p!='_' && *p!='/'; p--);
  172.     if(p>sbuf && *p=='_') *p=0;
  173.     snprintf(sbuf+strlen(sbuf),sizeof(sbuf)-strlen(sbuf),"/var.stat");
  174.     snprintf(tbuf,sizeof(tbuf),"%s=%s",name,val);
  175.     setdef(sbuf,tbuf); setvar(name,val);
  176. }
  177.  
  178.         /* The session is probably robot. */
  179. void robot_doubt(void)
  180. {
  181.     char *h, *p;
  182.  
  183.     p=getvar("special_parm"); h=getvar("module");
  184.     if(p==NULL || h==NULL) {
  185.         bad: user_error("robot_doubt"); return;
  186.     }
  187.     p=find_word_start(p); strip_trailing_spaces(p);
  188.     if(strcmp(p,"wims")!=0 || strcmp(h,home_module)!=0) goto bad;
  189.     set_static_session_var("wims_robotcheck","manual");
  190. }
  191.  
  192.         /* User has changed module within an operation.
  193.          * Probably due to robot access. */
  194. void bad_module(void)
  195. {
  196.     char *p;
  197.     p=getvar("wims_user"); if(p==NULL) p="";
  198.     if(*p==0 && strcmp(robotcheck,"manual")!=0) set_static_session_var("wims_robotcheck","robot");
  199.     else setvar("wims_human_access","yes");
  200.     user_error("module_change");
  201. }
  202.  
  203.         /* returns 1 if session directory exists */
  204. int session_exists(char *s)
  205. {
  206.     if(ftest(mkfname(NULL,"../%s/%s/var",SESSION_BASE,s))==is_file) return 1;
  207.     else return 0;
  208. }
  209.  
  210.         /* Check the validity of session number .
  211.          * returns 0 if OK, else -1. */
  212. int check_session(void)
  213. {
  214.     char tbuf[MAX_LINELEN+1], vbuf[MAX_LINELEN+1];
  215.     char *p, *pp, *pr;
  216.     int i,m,n,pl,rapid,badmod;
  217.     struct stat st;
  218.  
  219.     rapid=badmod=0; pr="";
  220.     if(fopen_session_var_file("r")==NULL) return -1;
  221.     if(ftest(s2_prefix)!=is_dir) mkdirs(s2_prefix);
  222.     session_var_ready=1; memmove(&svar_file,&m_file,sizeof(WORKING_FILE));
  223.         /* REMOTE_ADDR */
  224.     wgetline(vbuf,MAX_LINELEN,&m_file);
  225.     mystrncpy(last_host,vbuf+strlen("REMOTE_ADDR="),sizeof(last_host));
  226.     m_file.linepointer++; /* now it points to query_string */
  227.     pp=getenv("QUERY_STRING");
  228.     if(pp!=NULL && *pp!=0 && strlen(pp)<=MAX_LINELEN) {
  229.                 /* we compare the query string with the last one. */
  230.         char *p1, *p2;
  231.         wgetline(tbuf,MAX_LINELEN,&m_file);
  232.         p1=tbuf+strlen("QUERY_STRING=");
  233.         if(strncmp(tbuf,"QUERY_STRING=",strlen("QUERY_STRING="))==0 &&
  234.            strcmp(pp,p1)==0 && strstr(session_prefix,"_test")==NULL) {
  235.                         /* query string does not change */
  236.             if(ftest(mkfname(NULL,"%s/%s",s2_prefix,lastout))==is_file &&
  237.                ftest_size > 0) {
  238.                 uselast:
  239.                 putlastout(); delete_pid(); exit(0);
  240.             }
  241.             else {
  242.                 if(cmd_type==cmd_new || cmd_type==cmd_renew ||
  243.                    cmd_type==cmd_reply || cmd_type==cmd_next) {
  244.                     cmd_type=cmd_resume;
  245.                     force_setvar(ro_name[ro_cmd],"resume");
  246.                     forceresume=1;                 
  247.                 }
  248.             }
  249.         }
  250.                 /* stop rapidfire requests */
  251.         if((cmd_type==cmd_new || cmd_type==cmd_renew) &&
  252.            strncmp(p1,"session=",strlen("session="))==0 &&
  253.            strncmp(pp,"session=",strlen("session="))==0) {
  254.             p1=strchr(p1,'&'); if(p1==NULL) p1="";
  255.             p2=strchr(pp,'&'); if(p2==NULL) p2=""; pr=p2;
  256.             if(strcmp(p1,p2)==0) rapid=1;
  257.         }
  258.     }
  259.     m_file.linepointer=3;
  260.     wgetline(vbuf,MAX_LINELEN,&m_file); /* stored user_agent */
  261. /*    p=getenv("HTTP_USER_AGENT"); if(p==NULL) p="";
  262.     if(strcmp(vbuf+strlen("HTTP_USER_AGENT="),p)!=0) bad_ident(); */
  263.     m_file.linepointer=HEADER_VAR_NO;
  264.     pl=strlen(var_prefix);i=-1;
  265.     while(wgetline(tbuf,MAX_LINELEN,&m_file)!=EOF) {
  266.         if(tbuf[0]==0) break;   /* blank line */
  267.         if(strncmp(tbuf,var_prefix,pl)!=0) break;
  268.         i++;if(i>=RO_NAME_NO) break;
  269.         for(n=0;n<varget_no && varget[n]!=i;n++);
  270.         if(n>=varget_no) continue;
  271.         m=pl+strlen(ro_name[i]);
  272.         if(tbuf[m]!='=' || tbuf[m+1]==0) continue;
  273.         if(i==ro_module && cmd_type!=cmd_new && cmd_type!=cmd_intro) {
  274.             char *pp;
  275.             pp=getvar(ro_name[i]);
  276.             if(pp!=NULL && *pp!=0 && strcmp(pp,tbuf+m+1)!=0) badmod=1;
  277.         }
  278.         if(i==ro_lang && !user_lang)
  279.           force_setvar(ro_name[i],tbuf+m+1);
  280.         else setvar(ro_name[i],tbuf+m+1);
  281.     }
  282.         /* recover internal variables */
  283.     do {
  284.         char *v;
  285.         if(tbuf[0]==0) break;
  286.         v=strchr(tbuf,'=');
  287.         if(v==NULL) break; else *(v++)=0;
  288.         if(strncmp(tbuf,var_prefix,strlen(var_prefix))!=0) setenv(tbuf,v,1);
  289.         else if(tbuf[strlen(var_prefix)]) force_setvar(tbuf+strlen(var_prefix),v);
  290.     }
  291.     while(wgetline(tbuf,MAX_LINELEN,&m_file)!=EOF);
  292.     get_static_session_var();
  293.     robotcheck=getvar("wims_robotcheck"); if(robotcheck==NULL) robotcheck="";
  294.         /* form access means manual access. Mark this. */
  295.     if(form_access && strcmp(robotcheck,"manual")!=0) {
  296.         robotcheck="manual";
  297.         set_static_session_var("wims_robotcheck","manual");
  298.     }
  299.     else if(strcmp(robotcheck,"robot")==0) robot_doubt();
  300.     if(badmod) bad_module();
  301.     if(cookiegot[0]!=0) {
  302.         p=getvar("wims_sescookie");
  303.         if(p!=NULL && *p!=0 && strcmp(cookiegot,p)!=0) bad_ident();
  304.     }
  305.     p=getvar("wims_sreferer");
  306.     if(p!=NULL && *p!=0) {
  307.         setenv("HTTP_REFERER",p,1); setvar("httpd_HTTP_REFERER",p);
  308.     }
  309.     if(rapid) {
  310.         int rapidfiredelay;
  311.         char *pw, fnbuf[MAX_FNAME+1];
  312.                 /* Delay: 10 seconds within worksheets, 1 second otherwise. */
  313.         pw=getvar("wims_developer");
  314.         if(pw!=NULL && *pw!=0) goto delcheckend;
  315.         pw=getvar("wims_user");
  316.         if(pw==NULL || *pw==0 || strcmp(pw,"supervisor")==0) rapidfiredelay=1;
  317.         else {
  318.             pw=strstr(pr,"&+worksheet=");
  319.             if(pw!=NULL && myisdigit(*(pw+strlen("&+worksheet=")))) rapidfiredelay=10;
  320.             else rapidfiredelay=2;
  321.         }
  322.         if(ftest(mkfname(fnbuf,"%s/%s",s2_prefix,lastout))==is_file
  323.            && ftest_size > 0
  324.            && stat(fnbuf,&st) == 0
  325.            && st.st_mtime > nowtime-rapidfiredelay && st.st_mtime <= nowtime)
  326.           goto uselast;
  327.     }
  328.         /* set protocol string */
  329.     delcheckend: pp=getvar("wims_protocol");
  330.     if(pp!=NULL && strcmp(pp,"https")==0) {
  331.         protocol="https"; set_protocol();
  332.     }
  333.     useropts(); return 0;
  334. }
  335.         /* check whether a session is trapped. */
  336. void trap_check(char *s)
  337. {
  338.     char buf[64];
  339.     char *p;
  340.     time_t t1;
  341.  
  342.     setvar("wims_session_expired",s);
  343.     accessfile(tmplbuf,"r","../tmp/log/trap.check");
  344.     if(tmplbuf[0]==0) return;
  345.     p=getenv("REMOTE_ADDR");if(p==NULL) return;
  346.     snprintf(buf,sizeof(buf),":%s,%s,",s,p);
  347.     p=strstr(tmplbuf,buf); if(p==NULL) return;
  348.     p+=strlen(buf);*find_word_end(p)=0;
  349.     t1=atoi(p);
  350.     if(t1>nowtime) user_error("trapped");
  351. }
  352.  
  353. char cars[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  354.  
  355. void set_cookie(void)
  356. {
  357.     #define keylen 20
  358.     char sesbuf[16], keybuf[keylen+8];
  359.     char *p;
  360.  
  361.     p=getvar(ro_name[ro_session]); if(p==NULL) return;
  362.     mystrncpy(sesbuf,p,sizeof(sesbuf));
  363.     if(strchr(sesbuf,'_')==NULL) {      /* main session */
  364.         int i;
  365.         for(i=0;i<keylen;i++) keybuf[i]=cars[random()%36];
  366.         keybuf[keylen]=0; cookiegot[0]=0;
  367.         snprintf(cookieset,sizeof(cookieset),"%s-%s",sesbuf,keybuf);
  368.         set_static_session_var("wims_sescookie",cookieset);
  369.         setcookie=1;
  370.     }
  371.     else {      /* subsession */
  372.         p=getvar("wims_sescookie"); if(p && *p)
  373.           mystrncpy(cookieset,p,sizeof(cookieset));
  374.     }
  375. }
  376.  
  377.         /* create a session number */
  378. void create_session(void)
  379. {
  380.     long t; char session_str[64],*s;
  381.     char *p, ses_dir_buf[MAX_FNAME+1], sesrandbuf[MAX_LINELEN+1];
  382.     int i;
  383.    
  384.         /* no session is created for robots */
  385.     if(robot_access) return;
  386.     sesrandbuf[0]=0;
  387.         /* If session is given in request_string: use it. */
  388.     s=getvar(ro_name[ro_session]); if(s==NULL) goto creat;
  389.     mystrncpy(session_str,s,sizeof(session_str));
  390.     s=strchr(session_str,'.'); if(s!=NULL) *s=0;
  391.     s=session_str;
  392.     if(*s!=0) {
  393.         int i;
  394.         mkfname(ses_dir_buf,"%s/%s",session_dir,s);
  395.         i=ftest(ses_dir_buf);
  396.         if(i<0) {
  397.             trap_check(s);
  398.                 /* subsession */
  399.             if(strlen(s)>10 && strchr(s,'_')!=NULL) {
  400.                 char *tt;
  401.                 tt=strrchr(ses_dir_buf,'_'); if(tt!=NULL) *tt=0;
  402.                 /* parent session gone. */
  403.                 if(ftest(ses_dir_buf)<0) goto creat;
  404.                 goto creat2;
  405.             }
  406.             else goto creat;
  407.         }
  408.         if(i!=is_dir) {
  409.             trap_check(s);
  410.             remove_tree(ses_dir_buf); goto creat;
  411.         }
  412.         return;
  413.     }
  414.     creat:
  415.     t=create_job_ident();
  416.     for(i=0;i<MAX_SESRANDOM;i++)
  417.       snprintf(sesrandbuf+strlen(sesrandbuf),
  418.                sizeof(sesrandbuf)-strlen(sesrandbuf),
  419.                "%d,",sesrandomtab[i]);
  420.     sesrandbuf[strlen(sesrandbuf)-1]='\n';
  421.     snprintf(session_str,sizeof(session_str),"%c%c%08lX",
  422.              cars[random()%36],cars[random()%36],t);
  423.     creat2:
  424.     force_setvar(ro_name[ro_session],session_str);
  425.     setsesdir(session_str);
  426.         /* check whether the environment is created. */
  427.     s=getvar(ro_name[ro_session]);
  428.     if(s==NULL || strcmp(s,session_str))
  429.       internal_error("cannot_create_session_number");
  430.     snprintf(ses_dir_buf,sizeof(ses_dir_buf)-100,"%s/%s",
  431.              session_dir,session_str);
  432.     if(mkdir(ses_dir_buf,S_IRWXU)==-1)
  433.       internal_error("cannot_create_session_directory");
  434.     mkfname(s2_prefix,"%s/%s",s2_dir,session_str);
  435.     if(mkdir(s2_prefix,S_IRWXU)==-1) mkdirs(s2_prefix);
  436.     mystrncpy(session_prefix,ses_dir_buf,sizeof(session_prefix)); create_pid();
  437.     if(strchr(session_str,'_')==NULL) {
  438.         if((s=getenv("HTTP_REFERER"))!=NULL && *s!=0 && strlen(s)<MAX_FNAME-20
  439.            && strstr(s,"wims")==NULL) {
  440.             char *tt;
  441.             tt=getenv("SERVER_NAME");
  442.             if(tt==NULL || *tt==0 || strstr(s,tt)==NULL)
  443.               set_static_session_var("wims_sreferer",s);
  444.         }
  445.         if(sesrandbuf[0]) set_static_session_var("wims_sesrandom",sesrandbuf);
  446.     }
  447.         /* determine http protocol name. How to detect? */
  448.     p=getenv("HTTPS"); if(p!=NULL && strcmp(p,"on")==0) {
  449.       protocol="https"; set_protocol();
  450.     }
  451.     force_setvar("wims_protocol",protocol);
  452.     new_session=1; session_serial=0;
  453.     setvar("wims_new_session","yes");
  454.     if(strchr(session_str,'_')!=NULL) get_static_session_var();
  455.     set_cookie();
  456. }
  457.  
  458.         /* Register time of the request. */
  459. void set_req_time(void)
  460. {
  461.     char tstr[64];
  462.    
  463.     snprintf(tstr,sizeof(tstr),"%04d-%02d-%02d.%02d:%02d:%02d=%lu",
  464.             (now->tm_year)+1900, (now->tm_mon)+1, now->tm_mday,
  465.             now->tm_hour, now->tm_min, now->tm_sec, nowtime);
  466.     force_setvar("wims_req_time",tstr);
  467.     if(cmd_type == cmd_new || cmd_type == cmd_renew)
  468.       force_setvar("wims_module_start_time",tstr);
  469.     if(new_session) force_setvar("wims_session_start_time",tstr);
  470. }
  471.  
  472.         /* set up module_prefix. */
  473. void set_module_prefix(void)
  474. {
  475.     char tbuf[MAX_FNAME+1], mmbuf[MAX_FNAME+1], *p, *pp, *ps;
  476.     int t,ft;
  477.     struct stat st;
  478.  
  479.     isclassmodule=0;
  480.     p=getvar(ro_name[ro_module]);
  481.     if(p==NULL || *p==0) user_error("no_module_name");
  482.         /* security measure: we should not allow users to go back to
  483.          * parent directories. */
  484.     if(strstr(p,parent_dir_string)!=NULL) user_error("wrong_module");
  485.     if(strncmp(p,"classes/",strlen("classes/"))==0) isclassmodule=1;
  486.     if(strncmp(p,"devel/",strlen("devel/"))==0) isdevelmodule=1;
  487.     mkfname(module_prefix,"%s/%s",module_dir,p);
  488.         /* Now no symbolic link should appear in the module path. */
  489.     mkfname(tbuf,"modules/%s",p);
  490.     for(t=0,ps=pp=strchr(tbuf+strlen("modules/"),'/'); pp;
  491.         *pp='/', ps=pp, pp=strchr(pp+1,'/'), t++) {
  492.         *pp=0; if(lstat(tbuf,&st)) user_error("wrong_module");
  493.         if(t>0 && S_ISLNK(st.st_mode)) {
  494.             if(strcmp(ps,"/local")!=0 ||
  495.                strncmp(tbuf,"modules/home",strlen("modules/home"))==0)
  496.               user_error("wrong_module");
  497.        }
  498.     }
  499.         /* Check validity of the module. */
  500.     mkfname(tbuf,"%s/%s",module_prefix,html_file);
  501.     ft=stat(tbuf,&st);
  502.     if(ft!=0 && p[strlen(p)-3]!='.') {
  503.         int i,j;
  504.         char *l;
  505.         l=getvar(ro_name[ro_lang]);
  506.         j=available_lang_no;
  507.         for(i=-1;i<j && ft!=0;i++) {
  508.             if(i<0) mkfname(mmbuf,"%s.%s",p,l);
  509.             else mkfname(mmbuf,"%s.%s",p,available_lang[i]);
  510.             mkfname(module_prefix,"%s/%s",module_dir,mmbuf);
  511.             mkfname(tbuf,"%s/%s",module_prefix,html_file);
  512.             ft=stat(tbuf,&st);
  513.         }
  514.         if(ft==0) force_setvar(ro_name[ro_module],mmbuf);
  515.     }
  516.     if(ft!=0 && !isclassmodule) user_error("wrong_module");
  517.     setenv("module_dir",module_prefix,1); setvar("module_dir",module_prefix);
  518.     module_index();
  519. }
  520.  
  521.         /* set up session_prefix. */
  522. int set_session_prefix(void)
  523. {
  524.     char *p, s[32];
  525.  
  526.     if(robot_access) {
  527.         mystrncpy(session_prefix,robot_session,sizeof(session_prefix));
  528.         mystrncpy(s2_prefix,robot_session,sizeof(session_prefix));
  529.         return 0;
  530.     }
  531.     p=getvar(ro_name[ro_session]);
  532.     if(p==NULL || *p==0) user_error("no_session");
  533.         /* same reason as for modules */
  534.     if (strchr(p,'/')!=NULL || strstr(p,parent_dir_string)!=NULL
  535.         || *find_word_end(p)!=0) user_error("wrong_session");
  536.     mystrncpy(s,p,sizeof(s));
  537.     p=strchr(s,'.'); if(p!=NULL) *p=0;
  538.     mkfname(session_prefix,"%s/%s",session_dir,s);
  539.     p=strstr(session_prefix,"_mhelp"); if(p!=NULL) *p=0;
  540.     if(ftest(session_prefix)!=is_dir) return -1;
  541.     mkfname(s2_prefix,"%s/%s",s2_dir,s);
  542.     setenv("session_dir",session_prefix,1);
  543.     setenv("s2_dir",s2_prefix,1);
  544.     if(ftest(mkfname(NULL,"%s/.trap",s2_prefix))==is_file)
  545.       user_error("trapped");
  546.     return 0;
  547. }
  548.  
  549.         /* check reserved name values in query_string */       
  550. void parse_ro_names(void)
  551. {
  552.     int i;
  553.     char *cmd, *p;
  554.     char sesbuf[64];
  555.     create:
  556.     cmd=getvar(ro_name[ro_cmd]);
  557.     if(cmd==NULL || *cmd==0) user_error("no_command");
  558.     for(i=0;i<CMD_NO;i++) if(strcmp(cmd,commands[i])==0) break;
  559.     if(i>=CMD_NO) user_error("bad_command");
  560.     cmd_type=i;
  561.     if(cmd_type == cmd_new) {
  562.         create_session();
  563.         if(set_session_prefix()==0) {
  564.             check_session();
  565.             set_module_prefix();
  566.         }
  567.         else goto redo;
  568.     }
  569.     if (set_session_prefix()==-1 || (cmd_type != cmd_new && check_session())) {
  570.         redo:
  571.         force_setvar(ro_name[ro_cmd],commands[cmd_new]);
  572.         if(strcmp(ro_name[ro_module],home_module)!=0) user_var_no=0;
  573.         goto create;
  574.     }
  575.     if(!new_session) create_pid();
  576.     session_serial++;
  577.     if(robot_access) session_serial=1;
  578.     snprintf(sesbuf,sizeof(sesbuf),"%d",session_serial);
  579.     force_setvar("wims_session_serial",sesbuf);
  580.     p=getvar(ro_name[ro_session]);
  581.     if(p==NULL || *p==0) internal_error("parse_ro_names(): bad session.\n");
  582.     mystrncpy(sesbuf,p,sizeof(sesbuf));
  583.     p=strchr(sesbuf+5,'.'); if(p!=NULL) *p=0;
  584.     mktmpdir(sesbuf);
  585.     if(!robot_access) {
  586.         setsesdir(sesbuf);
  587.         p=strchr(sesbuf,'_');
  588.         if(p!=NULL) force_setvar("wims_subsession",p);
  589.     }
  590.     snprintf(sesbuf+strlen(sesbuf),sizeof(sesbuf)-strlen(sesbuf),
  591.              ".%d",session_serial);
  592.     force_setvar(ro_name[ro_session],sesbuf);
  593.     if(cmd_type != cmd_new) set_module_prefix();
  594.     set_req_time();
  595.     if(robot_access) check_load(0);
  596.     else {
  597.         if(new_session) auth();
  598.         else {
  599.             p=getvar("wims_user"); if(p==NULL || *p==0) check_load(2);
  600.         }
  601.     }
  602.     if(cmd_type==cmd_help && open_working_file(&m_file,module_about_file)==0)
  603.       var_proc(NULL,0);
  604. }
  605.  
  606.  
  607.         /* returns positive or 0 if var_def found, otherwise returns -1. */
  608. int var_def_check(char *name)
  609. {
  610.     char *p, nbuf[MAX_NAMELEN+1];
  611.     int i,tt;
  612.    
  613.     tt=-1;
  614.     for(p=name+strlen(name);p>name && myisdigit(*(p-1));p--);
  615.     if(*p && *p!='0' && p>name) tt=atoi(p);
  616.     else p=name+strlen(name);
  617.     if(p>name+MAX_NAMELEN) p=name+MAX_NAMELEN;
  618.     memmove(nbuf,name,p-name); nbuf[p-name]=0;
  619.     i=search_list(var_def,defined_var_total,sizeof(var_def[0]),nbuf);
  620.     if(i<0) return -1;
  621.     while(i>0 && tt<var_def[i].beg && strcmp(nbuf,var_def[i-1].name)==0) i--;
  622.     while(i<defined_var_total-1 && tt>var_def[i].end &&
  623.               strcmp(nbuf,var_def[i+1].name)==0) i++;
  624.     if(tt<var_def[i].beg || tt>var_def[i].end) return -1;
  625.     return i;
  626. }
  627.  
  628. int var_def_name(char *n, int v)
  629. {
  630.     char *q, *r;
  631.     int j;
  632.     if(strlen(n)>=MAX_NAMELEN) module_error("defn_too_long");
  633.     var_def[v].name=n;
  634.     if((strncmp(n,wims_prefix,wpflen)==0 &&
  635.         (strncmp(n,"wims_priv_",strlen("wims_priv_"))==0 ||
  636.          search_list(internal_name,INTERNAL_NAME_NO,
  637.                      sizeof(internal_name[0]),n+wpflen)>=0)) ||
  638.        search_list(ro_name,RO_NAME_NO,sizeof(ro_name[0]),n)>=0) {
  639.         setvar("wims_reserved_name",n);
  640.         module_error("name_is_reserved");
  641.     }
  642.     for(q=n;myisalnum(*q) || *q=='_'; q++);
  643.     if(q==n) {
  644.         illegal: setvar("wims_bad_name",n);
  645.         module_error("illegal_name");
  646.     }
  647.     if(*q=='[') {
  648.         *q++=0; r=find_matching(q,']');
  649.         if(r==NULL) goto illegal;
  650.         *r=0; j=atoi(q);
  651.         if(j<1) j=1; if(j>MAX_VAR_NUM) j=MAX_VAR_NUM;
  652.         var_def[v].beg=1; var_def[v].end=j;
  653.         return j;
  654.     }
  655.     if(*q) goto illegal;
  656.     for(r=q; r>n && myisdigit(*(r-1)); r--);
  657.     if(*r && *r!='0' && r>n) {
  658.         var_def[v].beg=var_def[v].end=atoi(r); *r=0;
  659.     }
  660.     else var_def[v].beg=var_def[v].end=-1;
  661.     return 1;
  662. }
  663.  
  664. int var_def_allow(char *p, int v)
  665. {
  666.     int i;
  667.     for(i=0;i<VAR_ALLOW_NO && strcasecmp(p,var_allow[i])!=0; i++);
  668.     if(i>=VAR_ALLOW_NO) module_error("bad_allow");
  669.     else var_def[v].allow=i;
  670.     return i;
  671. }
  672.  
  673. int varsort(const void *p1, const void *p2)
  674. {
  675.     int i; const struct VAR_DEF *pp1, *pp2;
  676.     pp1=p1; pp2=p2; i=strcmp(pp1->name,pp2->name);
  677.     if(i) return i; else return pp1->end - pp2->end;
  678. }
  679.  
  680.         /* parse module's variable definitions */
  681. void get_var_defs(void)
  682. {
  683.     int i, j, k, v, add;
  684.     char *p, *p1, *wlist[MAX_VAR_NUM];
  685.    
  686.     defined_var_total=0;
  687.     if(read_module_file(var_def_file)!=0) return;
  688.     var_def_buf=m_file.textbuf;
  689.     for(m_file.l=v=add=0;v<MAX_VAR_NUM && m_file.l<m_file.linecnt;m_file.l++) {
  690.         if(m_file.lines[m_file.l].isstart!=1) continue;
  691.         p=find_word_start(m_file.lines[m_file.l].address);
  692.         if(*p==0 || *p==comment_prefix_char) continue;  /* empty or comment lines */
  693.         items2words(p);
  694.         if((p1=strchr(p,':'))!=NULL) {  /* new format */
  695.             *p1=' '; i=cutwords(p,wlist,MAX_VAR_NUM); if(i<=1) continue;
  696.             k=var_def_allow(wlist[0],v);
  697.             for(j=1;j<i && v<MAX_VAR_NUM;j++) {
  698.                 add+=var_def_name(wlist[j],v); var_def[v].allow=k;
  699.                 v++;
  700.             }
  701.         }
  702.         else {
  703.             i=cutwords(p,wlist,3); if(i<2) module_error("too_few_columns");
  704.             add+=var_def_name(wlist[0],v); var_def_allow(wlist[1],v);
  705.             var_def[v].defined_in_parm=0;
  706.             v++;
  707.         }
  708.     }
  709.     if(v>=MAX_VAR_NUM) module_error("too_many_variables");
  710.     defined_var_total=v;
  711.     qsort(var_def,v,sizeof(var_def[0]),varsort);
  712.     p=getvar(ro_name[ro_module]);
  713.     if(p==NULL || strncmp(p,"devel/",6)!=0) return;
  714.     for(v=1;v<defined_var_total;v++) {
  715.         if(strcmp(var_def[v].name,var_def[v-1].name)==0 &&
  716.            var_def[v].beg<=var_def[v-1].end) {
  717.             setvar("wims_bad_name",var_def[v].name);
  718.             module_error("multiple_declaration");
  719.         }
  720.     }
  721. }
  722.  
  723.         /* returns 1 if hacked, else 0. */
  724. int try_hack(char *var)
  725. {
  726.     int i, al;
  727.     char vbuf[16];
  728.     i=var_def_check(var);
  729.     if(i<0) return 0;
  730.     al=var_def[i].allow;
  731.     if(al != var_allow_any) switch(cmd_type) {
  732.         case cmd_new:
  733.         case cmd_renew: {
  734.             if (al != var_allow_init && al != var_allow_config) return 0;
  735.             else break;
  736.         }
  737.         case cmd_config: {
  738.             if(al != var_allow_config) return 0;
  739.             else break;
  740.         }
  741.         case cmd_reply: {
  742.             if(al != var_allow_reply) return 0;
  743.             else break;
  744.         }
  745.         case cmd_help: {
  746.             if(al != var_allow_help) return 0;
  747.             else break;
  748.         }
  749.         default: return 0;
  750.     }
  751.     snprintf(vbuf,sizeof(vbuf),"%d",(int) irand(21));
  752.     var_hacking=1; setvar(var,vbuf); var_hacking=0;
  753.     return 1;    
  754. }
  755.    
  756.         /* set environ variables from last session save
  757.          * The session var file starts with variables which should not
  758.          * be restored. Variables which are restored follow a blank line. */
  759. void set_vars_from_session(void)
  760. {
  761.     char lbuf[MAX_LINELEN+1];
  762.     int i;
  763.     char *p;
  764.  
  765.     if(session_var_ready) memmove(&m_file,&svar_file,sizeof(WORKING_FILE));
  766.     else fopen_session_var_file("r");
  767.         /* look for the first blank line. */
  768.     for(i=0;i<m_file.linecnt && (m_file.lines[i].isstart==0 || m_file.lines[i].llen>0);i++);
  769.     for(i++;i<m_file.linecnt && m_file.lines[i].llen==0;i++);
  770.     if(i>=m_file.linecnt) return;
  771.     m_file.linepointer=i;
  772.     if(isdevelmodule && strstr(session_prefix,"_test")==NULL) isdevelmodule=0;
  773.     while(wgetline(lbuf,MAX_LINELEN, &m_file)!=EOF) {
  774.         p=strchr(lbuf,'=');
  775.         if(p==NULL || p<=lbuf || isspace(lbuf[0]) ) {
  776.                         /* this time it is corrupted var file */
  777.           call_ssh("cat %s/var >%s/corrupt.var.bak",session_prefix,log_dir);
  778.           internal_error("get_vars_from_session(): corrupt session variable file.");
  779.         }
  780.         *p=0;p++;
  781.                 /* Here we suppose that nobody can tamper session variable
  782.                  * file, and do not check variable names against module's
  783.                  * definition file. Policy under reserve. */
  784.             /* We do not allow override though.
  785.              * Especially because reply variables should
  786.              * be preserved. */
  787.         if(strncmp(lbuf,var_prefix,strlen(var_prefix))!=0)
  788.           setenv(lbuf,p,0);
  789.         else if(lbuf[strlen(var_prefix)]!=0 && getvar(lbuf+strlen(var_prefix))==NULL) {
  790.             if(!isdevelmodule || !try_hack(lbuf+strlen(var_prefix))) {
  791.                 setvar(lbuf+strlen(var_prefix),p);
  792.             }
  793.         }
  794.     }
  795.     close_working_file(&m_file,0);
  796. }
  797.  
  798.         /* Initialize environment variables according to module's
  799.          * variable init or calculation file.
  800.          * init is only used when cmd=new or renew.
  801.          * Requires get_var_defs be run first. */
  802. void var_proc(char *fname,int cache)
  803. {
  804.     int  t;
  805.     char *p, tbuf[MAX_LINELEN+1];
  806.  
  807.     if(fname!=NULL && read_module_file(fname)) return;
  808.     if(untrust&6) get_var_privileges();
  809.     while(m_file.linepointer<m_file.linecnt) {
  810.         t=m_file.lines[m_file.linepointer].isstart;
  811.         if((t&~2)!=1 || m_file.lines[m_file.linepointer].llen==0) {
  812.             m_file.linepointer++; continue;
  813.         }
  814.         wgetline(tbuf,MAX_LINELEN,&m_file); substnest=0;
  815.         p=find_word_start(tbuf); if(*p==0) continue;
  816.         if((t&2)!=0) exec_main(p+1);
  817.         else exec_set(p);
  818.     }
  819.     close_working_file(&m_file,cache);
  820. }
  821.  
  822.         /* Deposit the content of wims_deposit into a file */
  823. void var_deposit(char *p)
  824. {
  825.     char fn[MAX_FNAME+1];
  826.     int l,fd;
  827.     if(!trusted_module()) return;
  828.     if(deplen>0) l=deplen; else {
  829.         while(isspace(*p)) p++; l=strlen(p);
  830.     }
  831.     if(l<=0) return;
  832.     if(l>MAX_DEPOSITLEN) l=MAX_DEPOSITLEN; /* silent truncation, should not occur */
  833.     mkfname(fn,"%s/user-deposit",session_prefix);
  834.     fd=creat(fn,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if(fd==-1) return;
  835.     write(fd,p,l); close(fd);
  836.     snprintf(fn,sizeof(fn),"%u",l); setvar("wims_deposit_len",fn);
  837. }
  838.  
  839.         /* Check and set variables passed in query_string */
  840. void set_vars_from_parm(void)
  841. {
  842.     int i,j,al;
  843.     char *s, vbuf[MAX_LINELEN+1];
  844.     if(forceresume) return;
  845.     for(i=0; i<user_var_no; i++) {
  846.         j=var_def_check(user_variable[i].name);
  847.         if(j<0) continue;
  848.              /* check permissions */
  849.         al=var_def[j].allow;
  850.         if(al != var_allow_any) switch(cmd_type) {
  851.             case cmd_new:
  852.             case cmd_renew:
  853.                 if (al != var_allow_init && al != var_allow_config) {
  854. violat:             /* setvar(error_data_string,user_variable[i].name);
  855.                     user_error("allow_violation"); */
  856.                     goto loopend;
  857.                 }
  858.                 break;
  859.            
  860.             case cmd_config:
  861.                 if(al != var_allow_config) goto violat;
  862.                 break;
  863.  
  864.             case cmd_reply:
  865.                 if(al != var_allow_reply) goto violat;
  866.                 break;
  867.            
  868.             case cmd_help:
  869.                 if(al != var_allow_help) goto violat;
  870.                 break;
  871.            
  872.             default: goto violat;
  873.         }
  874.         var_def[j].defined_in_parm=1;
  875.         if(strcmp(user_variable[i].name,"wims_deposit")==0) {
  876.             var_deposit(user_variable[i].value); continue;
  877.         }
  878.         mystrncpy(vbuf,user_variable[i].value,sizeof(vbuf));
  879.         if(strchr(vbuf,'$')!=NULL) {
  880.             char *p;
  881.             while((p=strchr(vbuf,'$'))!=NULL)
  882.               string_modify(vbuf,p,p+1,"&#36;");
  883.         }
  884.         s=getvar(user_variable[i].name);
  885.         if(s==NULL || *s==0) setvar(user_variable[i].name, vbuf);
  886.         else {  /* concatenate */
  887.             int k;
  888.             k=strlen(s)+strlen(vbuf);
  889.             if(k>=MAX_LINELEN-2) user_error("string_too_long");
  890.             snprintf(tmplbuf,sizeof(tmplbuf),"%s, %s",s,vbuf);
  891.             setvar(user_variable[i].name, tmplbuf);        
  892.         }
  893.         loopend: ;
  894.     }
  895. }
  896.  
  897.         /* parms to be eliminated from module_init_parm */
  898. /* char *init_elim[]={
  899.     "module","cmd","session","lang","worksheet","wims_access","useropts"
  900. };
  901. #define init_elim_no (sizeof(init_elim)/sizeof(init_elim[0]))
  902. */
  903.  
  904. void elim_parm(char *str, char *parm)
  905. {
  906.     char *p1, *p2;
  907.     for(p1=strstr(str,parm);p1!=NULL;p1=strstr(p1+1,parm)) {
  908.         if( (p1>str && *(p1-1)!='&') || *(p1+strlen(parm))!='=')
  909.           continue;
  910.         p2=strchr(p1,'&');
  911.         if(p2==NULL) {
  912.             if(p1>str) *(p1-1)=0; else *p1=0;
  913.             return;
  914.         }
  915.         strcpy(p1,p2+1); p1--;
  916.     }
  917. }
  918.  
  919.         /* eliminate technical definitions form parameter string. */
  920. void prep_init_parm(char rqv[])
  921. {
  922.     int i;
  923.     char *p;
  924.  
  925.     for(p=strstr(rqv,"&+"); p!=NULL; p=strstr(++p,"&+"))
  926.       strcpy(p+1,p+2);
  927.     for(i=0;i<RO_NAME_NO;i++) elim_parm(rqv,ro_name[i]);
  928.     if(strlen(rqv)>=MAX_LINELEN) rqv[0]=0;
  929.     while(rqv[0]=='&') strcpy(rqv,rqv+1);
  930.     while(rqv[0]!=0 && rqv[strlen(rqv)-1]=='&') rqv[strlen(rqv)-1]=0;
  931. }
  932.  
  933.         /* retain initializing parameters, for use in user references */
  934. void set_init_parm(void)
  935. {
  936.     char *rq, rqv[MAX_LINELEN*2+2], *u, *sh;
  937.     char *shname;
  938.     int public_sheet;
  939.  
  940.     if(isexam) return;
  941.     force_setvar("wims_sheet",""); force_setvar("wims_exo","");
  942.     rq=getenv("QUERY_STRING");
  943.     if(rq==NULL || *rq==0) {
  944.         empty:
  945.         setvar("module_init_parm",""); return;
  946.     }
  947.     if(strlen(rq)>=MAX_LINELEN*2) goto empty;
  948.     _http2env(rqv,rq); prep_init_parm(rqv);
  949.     setvar("module_init_parm",rqv); public_sheet=0;
  950.         /* now determine the sheet number for user */
  951.     sh=getvar(ro_name[ro_worksheet]); if(sh==NULL) return;
  952.     if(*sh=='P') {public_sheet=1; sh++;}
  953.     shname="sheet";
  954.     u=getvar("wims_user"); if(u==NULL) u="";
  955.     if(sh!=NULL && *sh!=0) {
  956.         char buf[MAX_LINELEN+1],ubuf[32], nbuf[1024], *c, *m;
  957.         char *p1,*p2,*p3,*p4,*p5;
  958.         int i,j,sheet;
  959.         sheet=atoi(sh); if(sheet<=0 || sheet>256) return;
  960.         m=getvar(ro_name[ro_module]);
  961.         if(m==NULL) internal_error("set_init_parm(): module name disapears.");
  962.         if(*u==0) public_sheet=1;
  963.         if(!public_sheet) {
  964.             c=getvar("wims_class"); if(c==NULL) c="";
  965.             snprintf(nbuf,sizeof(nbuf),"%s/sheets/.%s%d",
  966.                      class_dir,shname,sheet);
  967.         }
  968.         else {
  969.             char bf[MAX_LINELEN+1];
  970.             int i;
  971.             accessfile(bf,"r","%s/.sheets",session_prefix);
  972.             if(bf[0]==0) return;
  973.             for(i=1, p1=bf;i<sheet;i++,p1=p2) {
  974.                 p2=strchr(p1,'\n');
  975.                 if(p2!=NULL) *p2++=0; else p2=p1+strlen(p1);
  976.             }
  977.             p2=strchr(p1,'\n'); if(p2) *p2=0;
  978.             snprintf(nbuf,sizeof(nbuf),"bases/sheet/%s.def",p1);
  979.         }
  980.         if(readfile(nbuf,buf,sizeof(buf))==NULL) return;
  981.         for(p1=strstr(buf,"&+");p1!=NULL;p1=strstr(++p1,"&+"))
  982.             strcpy(p1+1,p1+2);
  983.         if(strncmp(m,"classes/",strlen("classes/"))==0) {
  984.             m="classes/";
  985.             for(p1=strstr(buf,":classes/");p1;p1=strstr(p1+1,":classes/")) {
  986.                 if(p1==buf || *(p1-1)=='\n') {
  987.                     p1+=strlen(":classes/");
  988.                     p2=find_word_end(p1); if(p2>p1 && *p2=='\n') strcpy(p1,p2);
  989.                 }
  990.             }
  991.         }
  992.         snprintf(nbuf,sizeof(nbuf),":%s\n%s\n",m,rqv);
  993.         p1=strstr(buf,nbuf);
  994.         while(p1>buf && *(p1-1)!='\n') p1=strstr(p1+1,nbuf);
  995.         if(p1!=NULL) {
  996.             p2=strchr(buf,':');
  997.             while(p2>buf && *(p2-1)!='\n') p2=strchr(p2+1,':');
  998.             for(i=1;p2!=NULL && p2<p1;i++) {
  999.                 p2=strchr(p2+1,':');
  1000.                 while(p2>buf && *(p2-1)!='\n') p2=strchr(p2+1,':');
  1001.             }
  1002.             if(p2==NULL) return;        /* error which should not occur */
  1003.             snprintf(ubuf,sizeof(ubuf),"%d",i);
  1004.                 /* look for dependency information */
  1005.             for(j=0, p3=strchr(p1+strlen(nbuf),'\n');
  1006.                 j<3 && p3 && *(p3+1)!=':';
  1007.                 j++, p3=strchr(p3+1,'\n'));
  1008.             if(j>=3 && p3!=NULL && *(p3+1)!=':') {
  1009.                 p3++; p4=strchr(p3,'\n');
  1010.                 if(p4) {
  1011.                     *p4++=0; if(*p4!=':') {     /* options */
  1012.                         p5=strchr(p4,'\n'); if(p5) *p5=0;
  1013.                         force_setvar("wims_exoption",p4);
  1014.                     }
  1015.                 }
  1016.                 p3=find_word_start(p3); strip_trailing_spaces(p3);
  1017.                         /* non-empty dependency information */
  1018.                 if(*p3 && !public_sheet) {
  1019.                     exodepOK=depcheck(sh,i,p3);
  1020.                     if(!exodepOK) setvar("wims_exodep","pending");
  1021.                 }
  1022.             }
  1023.             if(public_sheet) {
  1024.                 char bf[32];
  1025.                 snprintf(bf,16,"P%s",sh);
  1026.                 force_setvar("wims_sheet",bf);
  1027.             }
  1028.             else force_setvar("wims_sheet",sh);
  1029.             force_setvar("wims_exo",ubuf);
  1030.             wims_sheet=sheet; wims_exo=i;
  1031.         }
  1032.     }
  1033. }
  1034.  
  1035.         /* user with class: whether exercise is registered
  1036.          * Returns 1 if got, 0 otherwise. */
  1037. int get_parmreg(void)
  1038. {
  1039.     char *p, *cl, *u, nbuf[MAX_FNAME+1];
  1040.     struct stat st;
  1041.  
  1042.     u=getvar("wims_user"); cl=getvar("wims_class");
  1043.     if(u==NULL || cl==NULL || *u==0 || *cl==0 || strcmp(u,"supervisor")==0
  1044.        || wims_sheet<=0 || wims_exo<=0) return 0;
  1045.     mkfname(nbuf,"%s/.parmreg/%s.%d.%d", class_dir,u,wims_sheet,wims_exo);
  1046.     p=getvar("wims_scorereg"); if(p!=NULL && strcmp(p,"suspend")==0) {
  1047.         unlink(nbuf); return 0;
  1048.     }
  1049.     if(stat(nbuf,&st)) return 0;
  1050.         /* latency is 10 min. */
  1051.     if(st.st_mtime<nowtime-600 || st.st_mtime > nowtime) {
  1052.         unlink(nbuf); return 0;
  1053.     }
  1054.     if(open_working_file(&m_file,nbuf)!=0) return 0;
  1055.     mkfname(m_file.name,"parmreg/%s.%d.%d",u,wims_sheet,wims_exo);
  1056.     while(wgetline(tmplbuf,MAX_LINELEN, &m_file)!=EOF) {
  1057.         p=strchr(tmplbuf,'=');
  1058.         if(p==NULL || p<=tmplbuf || isspace(tmplbuf[0]) )
  1059.                         /* this time it is corrupted var file */
  1060.           internal_error("get_parmreg(): corrupt parmreg file.");
  1061.         *p=0;p++;
  1062.         if(strncmp(tmplbuf,var_prefix,strlen(var_prefix))!=0) setenv(tmplbuf,p,1);
  1063.         else if(tmplbuf[strlen(var_prefix)]!=0) force_setvar(tmplbuf+strlen(var_prefix),p);
  1064.     }
  1065.     parm_restore=1;
  1066.     close_working_file(&m_file,0); return 1;
  1067. }
  1068.  
  1069.         /* set environment variables */
  1070. void set_variables(void)
  1071. {
  1072.     outputing=0; readnest=0;
  1073.     get_var_defs();
  1074.     set_vars_from_parm();
  1075.     if(cmd_type != cmd_new && cmd_type != cmd_renew) set_vars_from_session();
  1076.     else {
  1077.         set_init_parm();
  1078.         if(wims_sheet>0 && get_parmreg()) {
  1079.             cmd_type=cmd_resume; force_setvar("cmd","resume");
  1080.             var_proc(main_var_proc_file,0); return;
  1081.         }
  1082.         checkrafale();
  1083.         var_proc(var_init_file,0);
  1084.     }
  1085.     /* check_var_bounds(); */
  1086.     var_proc(main_var_proc_file,0);
  1087. }
  1088.  
  1089.         /* Output a phtml file. */
  1090. void phtml_put(char *fname,int cache)
  1091. {
  1092.     int t;
  1093.     char tbuf[MAX_LINELEN+1];
  1094.  
  1095.     outputing=1;
  1096.      /* File not found; we give empty output, but no error message. */
  1097.     if(fname!=NULL && read_module_file(fname)!=0) return;
  1098.     if(untrust&6) get_var_privileges();
  1099.     while(m_file.linepointer<m_file.linecnt) {
  1100.         t=m_file.lines[m_file.linepointer].isstart;
  1101.         if((t&~18)!=1) {m_file.linepointer++; continue;}
  1102.         wgetline(tbuf,MAX_LINELEN,&m_file); substnest=0;
  1103.         if((t&2)!=0) {exec_main(tbuf+1); continue;}
  1104.         substit(tbuf); output0(tbuf); _output_("\n");
  1105.     }
  1106.     close_working_file(&m_file,cache);
  1107. }
  1108.  
  1109.         /* output a file in base html directory. Internal use only. */
  1110. void phtml_put_base(char *fname,int cache)
  1111. {
  1112.     WORKING_FILE save;
  1113.     char modsave[MAX_FNAME+1];
  1114.     memmove(&save,&m_file,sizeof(WORKING_FILE));
  1115.     mystrncpy(modsave,module_prefix,sizeof(modsave));
  1116.     strcpy(module_prefix,"html");
  1117.     phtml_put(fname,cache);
  1118.     mystrncpy(module_prefix,modsave,sizeof(module_prefix));
  1119.     memmove(&m_file,&save,sizeof(WORKING_FILE));
  1120. }
  1121.  
  1122.         /* Read main.phtml, process it, and write to stdout. */
  1123. void main_phtml_put(char *mname)
  1124. {
  1125.     char *p, buf[1024], txbuf[256], bgbuf[256];
  1126.     char *bcolor, *refcolor, *bg, *tx;
  1127.     define_html_header(); readnest=0;
  1128.     nph_header(200);
  1129.     p=getvar("wims_backslash_insmath");
  1130.     if(p!=NULL && strcasecmp(p,"yes")==0) backslash_insmath=1;
  1131.     p=getvar("wims_expire");
  1132.     if(p!=NULL) p=strstr(p,"no-cache");
  1133.     if(p!=NULL) _output_("Cache-Control: no-cache\r\nPragma: no-cache\r\n");
  1134.     output("Server: %s %s (%s)\n", SHORTSWNAME,wims_version,LONGSWNAME);
  1135.     if(!robot_access && strcasecmp(usecookie,"yes")==0 && setcookie
  1136.        && mode!=mode_popup) {
  1137.         if(cookieset[0]==0) {
  1138.             p=getvar("wims_sescookie");
  1139.             if(p!=NULL && *p!=0) mystrncpy(cookieset,p,sizeof(cookieset));
  1140.         }
  1141.         output("Set-Cookie: %s%s; path=/\r\n",cookieheader,cookieset);
  1142.     }
  1143.     p=getvar("wims_main_font");
  1144.     if(p!=NULL && *p!=0) output("Content-type: text/html; charset=%s\r\n\r\n",p);
  1145.     else _output_("Content-type: text/html\r\n\r\n");
  1146.     bcolor=getvar("wims_bgcolor");
  1147.     if(bcolor==NULL || *bcolor==0) bcolor=bgcolor;
  1148.     refcolor=getvar("wims_ref_bgcolor");
  1149.     if(refcolor==NULL || *refcolor==0) {
  1150.         setvar("wims_ref_bgcolor","white");
  1151.         refcolor="white";
  1152.     }
  1153.     bg=getvar("wims_bgimg"); bgbuf[0]=0;
  1154.     if(bg!=NULL && *bg!=0 && strchr(bg,'\"')==NULL) {
  1155.         if(strchr(bg,'/')==NULL)
  1156.           snprintf(bgbuf,sizeof(bgbuf),"background=\"gifs/bg/%s\"",bg);
  1157.         else
  1158.           snprintf(bgbuf,sizeof(bgbuf),"background=\"%s\"",bg);
  1159.     }
  1160.     tx=getvar("wims_textcolor");
  1161.     if(tx!=NULL && *tx!=0 && strchr(tx,'\"')==NULL) {
  1162.         snprintf(txbuf,sizeof(txbuf),"text=\"%s\"",tx);
  1163.     }
  1164.     else txbuf[0]=0;
  1165.     snprintf(buf,sizeof(buf),
  1166.              "bgcolor=\"%s\" %s %s link=\"blue\" vlink=\"blue\"",
  1167.              bcolor,txbuf, bgbuf);
  1168.     setvar("wims_htmlbody",buf);
  1169.     phtml_put(mname,0);
  1170. }
  1171.  
  1172. void _write_var(char *name, FILE *varf,int user,int skip)
  1173. {
  1174.     char *s, buf[MAX_NAMELEN+9], nbf[MAX_NAMELEN+9];
  1175.  
  1176.     if((user&2)!=0) {
  1177.         snprintf(nbf,sizeof(nbf),"%s%s",wims_prefix,name); name=nbf;
  1178.     }
  1179.     if((user&1)!=0) {
  1180.         snprintf(buf,sizeof(buf),"%s%s",var_prefix,name); s=_getvar(name);
  1181.     }
  1182.     else {
  1183.         mystrncpy(buf,name,sizeof(buf)); s=getenv(name);
  1184.     }
  1185.     if(s==NULL) s="";
  1186.     if(skip && *s==0) return;
  1187.     fprintf(varf,"%s=",buf);
  1188.     if(strchr(s,'\n')==NULL) fputs(s,varf);
  1189.     else while(*s) {
  1190.           if(*s=='\n') fputc('\\',varf);
  1191.           fputc(*s,varf); s++;
  1192.     }
  1193.     fputc('\n',varf);
  1194. }
  1195.  
  1196. void _write_vars(FILE *varf)
  1197. {
  1198.     int i,j,k;
  1199.     char nbuf[MAX_NAMELEN+1];
  1200.     for(i=0;i<defined_var_total;i++) {
  1201.         if(var_def[i].beg>=0) {
  1202.             if(var_def[i].end<=var_def[i].beg) {
  1203.                 snprintf(nbuf,sizeof(nbuf),"%s%d",var_def[i].name,var_def[i].beg);
  1204.                 _write_var(nbuf,varf,1,1);
  1205.             }
  1206.             else {
  1207.                 char *pbuf[MAX_VAR_NUM];
  1208.                 j=varsuite(var_def[i].name,var_def[i].beg,var_def[i].end,pbuf,MAX_VAR_NUM);
  1209.                 for(k=0;k<j;k++) _write_var(pbuf[k],varf,1,1);
  1210.             }
  1211.         }
  1212.         else _write_var(var_def[i].name,varf,1,1);
  1213.     }
  1214. }
  1215.  
  1216.         /* save exercise parm for registered users */
  1217. void save_parmreg(void)
  1218. {
  1219.     char *p, *u, *sh, *ex, nbuf[MAX_FNAME+1], dbuf[MAX_FNAME+1];
  1220.     int s;
  1221.     FILE *varf;
  1222.  
  1223.     if(cmd_type!=cmd_reply && cmd_type!=cmd_new && cmd_type!=cmd_renew)
  1224.       return;
  1225.     u=getvar("wims_user");
  1226.     if(class_dir[0]==0 || *u==0) return;
  1227.     sh=getvar("wims_sheet"); ex=getvar("wims_exo");
  1228.     if(sh==NULL || ex==NULL || *sh==0 || *ex==0) return;
  1229.     mkfname(nbuf,"%s/.parmreg/%s.%s.%s",
  1230.              class_dir,u,sh,ex);
  1231.     if(cmd_type==cmd_reply) {
  1232.         unlink(nbuf); return;
  1233.     }
  1234.     p=getvar("wims_scorereg");
  1235.     if(p!=NULL && strcmp(p,"suspend")==0) return;
  1236.         /* these two lines must be before random factor
  1237.          * in order to set variable wims_scoring */
  1238.     s=atoi(sh); if(getscorestatus(getvar("wims_class"),s)==0) return;
  1239.     if(strcmp(u,"supervisor")==0) return;
  1240.         /* 0.2 is random factor to trigger exercise parm register */
  1241. /*    return;
  1242. */    if((double) random()>(double) RAND_MAX*0.2) return;
  1243.     mkfname(dbuf,"%s/.parmreg",class_dir);
  1244.     mkdirs(dbuf); varf=fopen(nbuf,"w"); if(varf==NULL) return;
  1245.     _write_var("module_init_parm",varf,1,0);
  1246.     _write_var("wims_sheet",varf,1,1);
  1247.     _write_var("wims_exo",varf,1,1);
  1248.     _write_var("wims_scoring",varf,1,1);
  1249.     _write_vars(varf);
  1250.     fclose(varf);
  1251. }
  1252.  
  1253. void exolog(char *fname)
  1254. {
  1255.     FILE *varf;
  1256.     varf=fopen(fname,"a");
  1257.     if(varf!=NULL) {
  1258.                 /* The first 4 lines should not be modified */
  1259.         fprintf(varf,"\n:\n");
  1260.         _write_var("QUERY_STRING",varf,0,0);
  1261.         _write_var("module",varf,1,0);
  1262.         _write_var("cmd",varf,1,0);
  1263.         _write_var("module_init_parm",varf,1,0);
  1264.         _write_var("wims_scoring",varf,1,1);
  1265.         _write_var("module_score",varf,1,1);
  1266.         fprintf(varf,"w_wims_checktime1=%lu\n\
  1267. w_wims_checktime2=%s\n",nowtime,nowstr);
  1268.         _write_vars(varf);
  1269.         fclose(varf);
  1270.     }
  1271. }
  1272.         /* save variables to session var file */
  1273. void save_session_vars(void)
  1274. {
  1275.     int i;
  1276.     char *mp, *sh, *ex, *ll;
  1277.     FILE *varf;
  1278.         /* light pages don't need saved variables. ? */
  1279. /*    if(varchr(module_prefix,"light")!=NULL) return;
  1280. */
  1281.     if(robot_access) return;
  1282.         /* no variable saving if cmd=help? */        
  1283.     if(cmd_type==cmd_help) return;
  1284.     lastdatafile[0]=lastftest[0]=0;
  1285.     lessrafale();
  1286.     mp=getvar("wims_nextmodule"); if(mp!=NULL && *mp!=0) {
  1287.         mp=getvar("module"); if(strcmp(mp,home_module)==0)
  1288.           force_setvar("module",getvar("wims_nextmodule"));
  1289.     }
  1290.     varf=fopen_session_var_file("w");
  1291.     for(i=0;i<HEADER_VAR_NO;i++)
  1292.       _write_var(header_var_name[i],varf,0,0);
  1293.     for(i=0;i<RO_NAME_NO;i++)
  1294.       _write_var(ro_name[i],varf,1,0);
  1295.     for(i=0;i<INTERNAL_NAME_NO;i++) {
  1296.         if(internal_name[i].stat==0)
  1297.           _write_var(internal_name[i].name,varf,3,0);
  1298.     }
  1299.     _write_var("password",varf,0,1);
  1300.     save_parmreg();
  1301.     if(new_session) fprintf(varf,"wims_new_session=yes\n");
  1302.     fprintf(varf,"\n");
  1303.     _write_var("module_init_parm",varf,1,0);
  1304.     _write_var("wims_sheet",varf,1,1);
  1305.     _write_var("wims_exo",varf,1,1);
  1306.     _write_var("wims_scoring",varf,1,1);
  1307.     _write_vars(varf);
  1308.     fclose(varf);
  1309.     if(cmd_type==cmd_new || cmd_type==cmd_renew || cmd_type==cmd_reply || cmd_type==cmd_next) {
  1310.         ll=getvar("wims_class_examlog");
  1311.         if(ll!=NULL && *ll!=0) i=atoi(ll); else i=examlog_limit;
  1312.         if(strstr(session_prefix,"_exam")!=NULL && examlogf[0]!=0 &&
  1313.            simuxam==0 && i>0) {
  1314.             mkdirs(examlogd); exolog(examlogf);
  1315.         }
  1316.         else {
  1317.             ll=getvar("wims_class_exolog");
  1318.             sh=getvar("wims_sheet"); ex=getvar("wims_exo");
  1319.             if(ll!=NULL && atoi(ll)>0 &&
  1320.                sh!=NULL && *sh!=0 && ex!=NULL && *ex!=0) {
  1321.                 char buf[MAX_FNAME+1];
  1322.                 mkfname(buf,"%s/exolog.%s.%s",session_prefix,sh,ex);
  1323.                 if(cmd_type==cmd_new || cmd_type==cmd_renew) unlink(buf);
  1324.                 exolog(buf);
  1325.             }
  1326.         }
  1327.     }
  1328.     if(var_def_buf) free(var_def_buf);
  1329. }
  1330.  
  1331.