Subversion Repositories wimsdev

Rev

Rev 16647 | 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.  
  18. /* Web exerciser */
  19.  
  20. #include "wims.h"
  21. enum Name_Modes NAME_MODES;
  22. enum Ro_Names RO_NAMES;
  23. enum _commands COMMANDS;
  24. WORKING_FILE m_file, svar_file, mcache[MAX_MCACHE];
  25. struct VAR_DEF var_def[MAX_VAR_NUM];
  26. char examlogf[MAX_FNAME+1];
  27. char mpboundary[1024];
  28. char *stdinbuf;
  29. struct user_variable user_variable[MAX_VAR_NUM];
  30. char available_lang[MAX_LANGUAGES][4];
  31.  
  32. struct {
  33.   char *name;
  34.   char *font;
  35. } charname[]={
  36.   {"en","windows-1252"},
  37.   {"fr","windows-1252"},
  38.   {"es","windows-1252"},
  39.   {"cn","gb2312"},
  40.   {"de","windows-1252"},
  41.   {"it","windows-1252"},
  42.   {"nl","windows-1252"},
  43.   {"si","iso-8859-2"},
  44.   {"ar","iso-8859-6"},
  45.   {"tw","big5"},
  46.   {"pt","windows-1252"},
  47.   {"ca","windows-1252"},
  48.   {"pt","windows-1252"},
  49.   {"ru","iso-8859-5"},
  50.   {"ty","iso-8859-13"}
  51. };
  52.  
  53. #define charname_no (sizeof(charname)/sizeof(charname[0]))
  54.  
  55. /* left to right or right to left writing */
  56. struct {
  57.   char *name;
  58.   char *dirn;
  59. } dirnname[]={
  60.   {"en","ltr"},
  61.   {"fr","ltr"},
  62.   {"es","ltr"},
  63.   {"cn","ltr"},
  64.   {"de","ltr"},
  65.   {"it","ltr"},
  66.   {"nl","ltr"},
  67.   {"si","ltr"},
  68.   {"ar","rtl"},
  69.   {"tw","ltr"},
  70.   {"pt","ltr"},
  71.   {"ca","ltr"},
  72.   {"pt","ltr"},
  73.   {"ru","ltr"},
  74.   {"ty","ltr"}
  75.  
  76. };
  77.  
  78. #define dirnname_no (sizeof(dirnname)/sizeof(dirnname[0]))
  79.  
  80.  
  81. #define evalue strevalue
  82. char *robot_session="../tmp/robot";
  83. int robot_access=0,human_access=0;
  84. int user_error_nolog=0;
  85. char *good_agent[]={
  86.   "Mozilla","Netscape","Opera","WIMS",
  87.   "MSIE","Konqueror","Java"
  88. };
  89. #define good_agent_no (sizeof(good_agent)/sizeof(good_agent[0]))
  90.  
  91. char *bad_agent[]={ /* These are really bad agents: prohibited. */
  92.   "HTTrack","MemoWeb","Teleport","Offline","Wget","eCatch",
  93.   "Powermarks","EmailSiphon", "WebCopier"
  94. };
  95. #define bad_agent_no (sizeof(bad_agent)/sizeof(bad_agent[0]))
  96.  
  97. /* used for debugging */
  98. int debug=0;
  99.  
  100. char class_dir[MAX_FNAME+1]; /* directory name of this class */
  101.  
  102. struct user_variable user_variable[MAX_VAR_NUM];
  103. int user_var_no;
  104.  
  105. struct VAR_DEF var_def[MAX_VAR_NUM];
  106. int defined_var_total;
  107.  
  108. /* Destinated to module error messages */
  109. WORKING_FILE m_file,svar_file,mcache[MAX_MCACHE];
  110. int mcachecnt;
  111.  
  112. /* Limit for any data working files. */
  113. int WORKFILE_LIMIT=2048*1024;
  114.  
  115. /* whether the user has defined language */
  116. int user_lang=0;
  117.  
  118. /* for instex grouping */
  119. int instex_cnt=0, getwimstexsize=1;
  120. char instex_src[MAX_LINELEN+1], instex_fname[MAX_LINELEN+1];
  121. char *instex_processor="tex..gif";
  122.  
  123. /* Cookie management */
  124. char cookiegot[256], cookieset[256], cookieheader[64]="WIMSUSER=";
  125.  
  126. /* multipart boundary */
  127. char mpboundary[1024];
  128. int  deplen=0; /* length of deposit */
  129.  
  130. int confset=0; /* set to 1 if setvar for config */
  131.  
  132. /* Operating mode: default, popup, raw, etc. */
  133.  
  134. int mode=mode_default;
  135.  
  136. /* Switch; notice subroutines wherether we are outputing. */
  137. int outputing;
  138.  
  139. char *home_module="home"; /* name of home module */
  140. extern char **environ;      /* table of environment variables */
  141. int module_defined=0;
  142.  
  143.         /* directory prefix buffers */
  144. char session_prefix[MAX_FNAME+1], s2_prefix[MAX_FNAME+1], module_prefix[MAX_FNAME+1];
  145.  
  146. char *stdinbuf;
  147. int sesrandomtab[MAX_SESRANDOM]; /* session random values */
  148. char multiexec_random[64];
  149. int executed_gotos; /* number of goto's executed. to check with GOTO_LIMIT. */
  150. int insert_no; /* number of instex, insplot, insPLOT. */
  151. int output_length; /* length of the output. */
  152. int isexam=0; /* non-zero if request is exam */
  153. int simuxam=0; /* exam is simulation */
  154. int is_multiexec=0; /* for execredirected */
  155. int multiexec_index;
  156. int direct_datafile=0;
  157. int exec_is_module=0;
  158.   /* root directory of modules */
  159. char *module_dir="modules";
  160. int new_session=0; /* =1 if new session created */
  161. int good_httpd=0; /* Whether the http server is intelligent */
  162. /* int internal_sql=0; */ /* for internal sql use */
  163. int direct_exec=0; /* calc routine is exected by exec if 1 */
  164. int print_precision=8; /* precision when printing real numbers */
  165. int session_serial; /* request serial for session control */
  166. int form_access=0; /* identifies form access, for robot identification */
  167. int lastout_file=-1; /* file to hold last output */
  168. char *instex_style=""; /* "": text "$": math "$$": displaymath */
  169. int instex_usedynamic=0; /* always dynamic if 1 */
  170. int wrapexec=0; /* if set to 1, change uid (nobody) to euid (wims).
  171.                  * if set to -1, change euid to uid when exec(). */
  172. int parm_restore=0; /* Restoring saved parameters? */
  173. int exec_wait=1; /* whether to wait for fork return */
  174. int execnt=0; /* count executions */
  175. int readnest; /* nested read count */
  176. int mfilecnt=0; /* count working files */
  177. int forceresume=0; /* force user to resume old request */
  178. int manageable=0; /* whether the connection may be site manager
  179.                    * 0: no; 1: maybe; 2: sure */
  180. int ismhelp=0;  /* 1 if session is in mhelp. */
  181. int getvar_len; /* length of the last-got variable. */
  182. int noout=0; /* if set to 1 then output is skipped */
  183. char tmp_dir[MAX_FNAME+1]; /* temporary directory */
  184. char *bin_dir="bin"; /* directory containing executable scripts and programs. */
  185. char cwdbuf[MAX_FNAME+1]; /* store current working directory */
  186. char var_hacking=0; /* Trying to hack a variable? */
  187. char *tmp_debug="no";
  188. char *tmp_debug_var="";
  189. char *tmp_debug_use_var="";
  190. char ins_alt[MAX_LINELEN+1]; /* dynamic insertion alternative text */
  191. char *devel_modules="close"; /* whether to open devel modules */
  192. int isclassmodule=0; /* 1 if the module is class module */
  193. int isdevelmodule=0; /* development module? */
  194. int setcookie=0; /* 1 if need to set cookie */
  195. int killpid=0; /* pid of process to kill by alarm */
  196. char *mathalign_sup1, *mathalign_sup2; /* see mathalign_base */
  197. int substnest=0; /* nesting level of substit() */
  198. int exodepOK=1;
  199. long int startmtime; /* start time in milliseconds */
  200. long int startmtime2; /* start time in microseconds */
  201. int backslash_insmath=0; /* \(...) substitution? */
  202. char examlogf[MAX_FNAME+1]; /* examlog file name */
  203. char examlogd[MAX_FNAME+1]; /* examlog directory name */
  204. char freeworklogf[MAX_FNAME+1]; /* freeworklog file name */
  205. char freeworklogd[MAX_FNAME+1]; /* freeworklog directory name */
  206. char exam_sheetexo[32]; /* sheet data of an exam */
  207. char loadavg[64];
  208. /* user file variable access control. */
  209. char *var_readable, *var_writable, *var_nr, *var_nw, *var_pfx;
  210. int hostcquota;
  211. int var_noexport; /* do not export variable */
  212.  
  213. char tmplbuf[MAX_LINELEN+1]; /* for temporary uses not thru subroutines. */
  214.  
  215. struct tm *now, Now; /* time of request */
  216. time_t nowtime, limtime, limtimex;
  217. char nowstr[32];
  218.  
  219. /* Resource limits. Capital names are reserved by system. */
  220. int rlimit_cpu=20;  /* cpu time in seconds */
  221. int rlimit_fsize=8388608;/* file size */
  222. int rlimit_as=614457600;/* virtual memory size */
  223. int rlimit_data=2004857600;/* data segment size; maxima requires a lot (must be lower than rlimit_as)*/
  224. int rlimit_stack=2097152;/* stack size */
  225. int rlimit_core=0; /* core dump size */
  226. int rlimit_rss=16777216; /* resident size */
  227. int rlimit_nproc=1024; /* number of processes */
  228. int rlimit_nofile=512; /* number of open files */
  229. int rlimit_memlock=2097152;/* locked-in-memory address space */
  230.  
  231. char *var_str; /* malloc'ed buffer to hold translated query_string */
  232.  
  233. /* buffer to hold module's variable definition file, malloc'ed. */
  234. char *var_def_buf;
  235.  
  236. /* job_identifier is even a reserved variable name */
  237. char job_identifier[32];
  238.  
  239. /* site manager definition IPv4 IPv6*/
  240. char *manager_site="127.0.0.1 ::1";
  241. int   manager_https=0;
  242.  
  243. /* sheet and exercise information */
  244. int wims_sheet=0,wims_exo=0;
  245.  
  246. /* Form method: get or post */
  247. char *default_form_method="post";
  248.  
  249. /* Je suis maintenant oblige de passer a l'anglais
  250.  * pour la langue de defaut.
  251.  */
  252. char lang[16]="en";
  253. char available_lang[MAX_LANGUAGES][4]={"en","fr"};
  254. int available_lang_no=2;
  255. char pre_language[4]="";
  256. FILE *trace_file;
  257. int trace_indent=0;
  258. char *protocol="http"; /* http or https */
  259.  
  260. /* check for coordinate input. This will mean that
  261.  * the request is manual, but not robot.
  262.  */
  263. int coord_input=0;
  264.  
  265. /* These are readonly environment variable names
  266.  * special parm used for special cmds (getins, etc).
  267.  */
  268. char *ro_name[]={
  269.   "cmd",
  270.   "empty",
  271.   "lang",
  272.   "module",
  273.   "session",
  274.   "special_parm",
  275.   "special_parm2",
  276.   "special_parm3",
  277.   "special_parm4",
  278.   "useropts" ,
  279.   "wims_session",
  280.   "wims_subsession",
  281.   "wims_window",
  282.   "worksheet"
  283. };
  284.  
  285. int RO_NAME_NO=(sizeof(ro_name)/sizeof(ro_name[0]));
  286.  
  287. int cmd_type;
  288. char *commands[]={
  289.     "intro" , "new" , "renew" , "reply" , "config" , "hint" , "help" ,
  290.       "resume", "next", "getins", "getframe", "getfile", "close", "ref"
  291. };
  292.  
  293. int CMD_NO=(sizeof(commands)/sizeof(commands[0]));
  294.  
  295. /* stat=0: saved variables
  296.  * all names starting with wims_priv_ are also internal.
  297.  */
  298. struct internal_name internal_name[]={
  299.   {"accessright", 1}, /* right to access commercial resources */
  300.   {"caller", 1}, /* caller session */
  301.   {"check", 1}, /* for exam check use */
  302.   {"class", 1},
  303.   {"class_examlog", 1},
  304.   {"class_exolog", 1},
  305.   {"class_limit", 1},
  306.   {"class_quota", 1},
  307.   {"class_regpass", 1},
  308.   {"class_user_limit", 1},
  309.   {"classdir", 1},
  310.   {"classname", 1},
  311.   {"devel_modules", 1},
  312.   {"developer", 1},
  313.   {"doc_quota", 1},
  314.   {"doc_regpass", 1},
  315.   {"email", 1},
  316.   {"exo", 0}, /* exercise number */
  317.   {"exoption", 1}, /* exercise option */
  318.   {"exotrymax", 0},
  319.   {"firstname", 1},
  320.   {"forum_limit", 1},
  321.   {"fwexo",0},   /*numero d'exo dans un freework */
  322.   {"fwnumber",0 },   /* numero de freework */
  323.   {"home", 1},
  324.   {"institutionname", 1},
  325.   {"isexam", 0}, /* whether the sheet is an exam sheet */
  326.   {"ismanager", 0},
  327.   {"lastname", 1},
  328.   {"mode", 0}, /* operating mode */
  329.   {"module_start_time", 0},
  330.   {"now", 1}, /* date and time, yyyymmdd.hh:mm:ss */
  331.   {"nowseconds", 1}, /* date and time, seconds since EPOCH */
  332.   {"nr", 1}, /* non-readable variables in user file, words */
  333.   {"nw", 1}, /* non-writable variables in user file, words */
  334.   {"otherclass", 1}, /* Remember other logins */
  335.   {"participate", 1}, /* superclass definition */
  336.   {"prefix", 1}, /* user file prefix */
  337.   {"protocol", 0}, /* http protocol */
  338.   {"rafale", 0}, /* rapidfire request information */
  339.   {"readable", 1}, /* readable variables in user file, words */
  340.   {"realuser", 1}, /* real user for supervisor in gateway */
  341.   {"req_time", 0}, /* time of the request */
  342.   {"sclassdir", 1},
  343.   {"scorereg", 0}, /* score registration flag */
  344.   {"seed", 0},
  345.   {"seed_repeat",0},
  346.   {"seed_score", 0},
  347.   {"seedcnt",0},
  348.   {"seedlastcnt",0},
  349.   {"sequence", 0}, /* sequence number */
  350.   {"sescookie", 1}, /* session cookie */
  351.   {"sesdir", 1},
  352.   {"session_serial", 0}, /* request serial in the session */
  353.   {"session_start_time", 0},
  354.   {"sheet", 0}, /* sheet number */
  355.   {"sup_secure", 1}, /* secure level of supervisor */
  356.   {"superclass", 1}, /* superclass code */
  357.   {"superclass_quota", 1},
  358.   {"supertype", 1}, /* superclass type */
  359.   {"supervise", 1}, /* superclass definition */
  360.   {"supervisor", 1}, /* real name of the supervisor */
  361.   {"supervisormail",1}, /* email of supervisor */
  362.   {"trustfile", 1}, /* trusted files in special adm modules */
  363.   {"useropts", 1}, /* user options */
  364.   {"writable", 1}, /* writable variables in user file, words */
  365. };
  366. int INTERNAL_NAME_NO=(sizeof(internal_name)/sizeof(internal_name[0]));
  367.  
  368. char *httpd_vars[]={
  369.   "HTTP_ACCEPT",
  370.   "HTTP_ACCEPT_CHARSET",
  371.   "HTTP_ACCEPT_LANGUAGE",
  372.   "HTTP_COOKIE",
  373.   "HTTP_HOST",
  374.   "HTTP_USER_AGENT",
  375.   "HTTP_X_REQUESTED_WITH",
  376.   "HTTPS",
  377.   "QUERY_STRING",
  378.   "REMOTE_HOST",
  379.   "REMOTE_ADDR",
  380.   "REMOTE_PORT",
  381.   "REQUEST_METHOD",
  382.   "SCRIPT_NAME",
  383.   "SERVER_NAME",
  384.   "SERVER_SOFTWARE",
  385.   "SERVER_PROTOCOL"
  386. };
  387. #define HTTPD_VAR_NO (sizeof(httpd_vars)/sizeof(httpd_vars[0]))
  388.  
  389. /* security: these variables will not be visible to child processes */
  390. char *unsetvars[]={
  391.   "DOCUMENT_ROOT","SERVER_SIGNATURE","SERVER_SOFTWARE",
  392.       "UNIQUE_ID","HTTP_KEEP_ALIVE","SSL_SESSION_ID"
  393. };
  394. #define unsetvarcnt (sizeof(unsetvars)/sizeof(unsetvars[0]))
  395.  
  396. int httpd_type=httpd_apache;
  397.  
  398. char *remote_addr=""; /* storing for performance */
  399. char *remote_host="";
  400.  
  401. char ref_name[2048], ref_base[2048];
  402.  
  403. void put_special_page(char *pname);
  404. void useropts(void);
  405.  
  406. /* Make certain httpd variables readable by modules */
  407. void take_httpd_vars(void)
  408. {
  409.   int i;
  410.   char *p, buf[MAX_NAMELEN+1];
  411.   var_noexport=1;
  412.   for(i=0;i<HTTPD_VAR_NO;i++) {
  413.    snprintf(buf,sizeof(buf),"httpd_%s",httpd_vars[i]);
  414.    if((p=getenv(httpd_vars[i]))!=NULL) setvar(buf,p);
  415.   }
  416.   var_noexport=0;
  417.  
  418.   for(i=0;i<unsetvarcnt;i++) unsetenv(unsetvars[i]);
  419.    /* IPv4 IPv6*/
  420.   p=getenv("REMOTE_ADDR");if(p!=NULL && (strcmp(p,"127.0.0.1")==0 || strcmp(p,"::1")==0)) human_access=1;
  421.   p=getenv("HTTP_REFERER"); if(p!=NULL && *p!=0) setvar("wims_referer",p);
  422. }
  423.  
  424. /* cookie2session */
  425. void cookie2session(void)
  426. {
  427.   char cksession[64], psession[32], *ckey, *p;
  428.   char nbuf[MAX_FNAME+1];
  429.  
  430.   if(mode==mode_popup) return;
  431.   if(cookiegot[0]==0) {
  432.    ckset: cookiegot[0]=0; setcookie=1; return;
  433.   }
  434.   p=getvar("special_parm");
  435.   if(p!=NULL && strcmp(p,"ignorecookie")==0) return;
  436.   mystrncpy(cksession,cookiegot,sizeof(cksession));
  437.   ckey=strchr(cksession,'-');
  438.   if(ckey==NULL) goto ckset; else *ckey++=0;
  439.   p=getvar("wims_session"); if(p==NULL) p="";
  440.   if(strstr(p,"new")!=NULL) goto ckset;
  441.   mystrncpy(psession,p,sizeof(psession));
  442.   p=strchr(psession,'_'); if(p!=NULL) *p=0;
  443.   if(psession[0]!=0) {
  444.     if(strcmp(psession,cksession)==0) return;
  445.     if(session_exists(psession)) goto ckset;
  446.     if(session_exists(cksession)) goto change;
  447.   }
  448.   else {
  449.     if(!session_exists(cksession)) return;
  450.     change:
  451.     p=getenv("HTTPS");
  452.     if(p!=NULL && strcasecmp(p,"on")==0) goto ckset;
  453.     mkfname(nbuf,"%s/%s/var",session_dir,cksession);
  454.     getdef(nbuf,"w_wims_ismanager",tmplbuf);
  455.     if(tmplbuf[0]!=0 && tmplbuf[0]!='0') goto ckset;
  456.     getdef(nbuf,"w_wims_protocol",tmplbuf);
  457.     if(strcasecmp(tmplbuf,"https")==0) goto ckset;
  458.     mkfname(nbuf,"%s/%s/var.stat",session_dir,cksession);
  459.     getdef(nbuf,"wims_user",tmplbuf);
  460.     if(tmplbuf[0]!=0) goto ckset;
  461.     force_setvar(ro_name[ro_session],cksession);
  462.     setsesdir(cksession);
  463.     force_setvar("wims_subsession","");
  464.     session_serial=0;
  465.   }
  466. }
  467.  
  468. void determine_font(char *l)
  469. {
  470.   int i;
  471.  
  472.   if(l==NULL || *l==0) return;
  473.   for(i=0;i<charname_no && memcmp(charname[i].name,l,2);i++);
  474.   if(i<charname_no) setvar("wims_main_font",charname[i].font);
  475. }
  476.  
  477. void determine_dirn(char *l)
  478. {
  479.   int i;
  480.  
  481.   if(l==NULL || *l==0) return;
  482.   for(i=0;i<dirnname_no && memcmp(dirnname[i].name,l,2);i++);
  483.   if(i<dirnname_no) setvar("wims_main_dirn",dirnname[i].dirn);
  484. }
  485.  
  486. void predetermine_language(void)
  487. {
  488.   char *p;
  489.   int i,n;
  490.  
  491.   if(pre_language[0]!=0) p=pre_language;
  492.   else p=getenv("HTTP_ACCEPT_LANGUAGE");
  493.   if(p!=NULL && strlen(p)>=2) {
  494.     for(i=0;i<available_lang_no && memcmp(p,available_lang[i],2)!=0;i++);
  495.     if(i<available_lang_no) goto lend;
  496.   }
  497.   p=getenv("HTTP_USER_AGENT");
  498.   if(p!=NULL && strlen(p)>=5) {
  499.     char *q;
  500.     if((q=strchr(p,'['))!=NULL && islower(*(q+1)) && islower(*(q+2)) && *(q+3)==']') {
  501.         char bb[4];
  502.         bb[0]=*(q+1);bb[1]=*(q+2);bb[2]=0;
  503.         for(i=0;i<available_lang_no && memcmp(bb,available_lang[i],2)!=0;i++);
  504.         if(i<available_lang_no) {
  505.           memmove(lang,bb,2); lang[2]=0;
  506.           goto lend2;
  507.         }
  508.     }
  509.   }
  510.   p=getenv("HTTP_HOST"); if(p==NULL) goto lend2;
  511.   n=strlen(p); if(n<=3 || *(p+n-3)!='.') goto lend2;
  512.   p=p+n-2;
  513.   for(i=0;i<available_lang_no && memcmp(p,available_lang[i],2)!=0;i++);
  514.   if(i<available_lang_no) {
  515.     lend: memmove(lang,p,2); lang[2]=0;
  516.     lend2: determine_font(lang);determine_dirn(lang);
  517.   }
  518. }
  519.  
  520. /* print a special page */
  521. void put_special_page(char *pname)
  522. {
  523.   determine_font(lang);
  524.   determine_dirn(lang);
  525.   phtml_put_base(mkfname(NULL,"%s.phtml.%s",pname,lang),0);
  526.   write_logs();free(var_str);
  527. }
  528.  
  529. /* check whether the connection is a site manager. */
  530. void manager_check(void)
  531. {
  532.   char *p, *pp, buf[16];
  533.   struct stat confstat;
  534.   int i;
  535.  
  536.   manageable=0;
  537.   if(robot_access || *manager_site==0 || checkhost(manager_site)<1)
  538.     goto mend;
  539.   if(manager_https) {
  540.     p=getenv("HTTPS");
  541.     if(p==NULL || strcmp(p,"on")!=0) goto mend;
  542.   }
  543. /* IPv4 IPv6*/
  544.   if(strcmp(remote_addr,"127.0.0.1")==0 || strcmp(remote_addr,"::1")==0) {
  545.     int port, port2;
  546.     char tester[128];
  547.     p=getenv("REMOTE_PORT"); if(p==NULL) goto mend;
  548.     port=atoi(p); if(port<1024 || port>65535) goto mend;
  549.     p=getenv("SERVER_PORT"); if(p==NULL) goto mend;
  550.     port2=atoi(p); if(port2>=10000 || port2<=0) goto mend;
  551. /* this is very non-portable */
  552.     manageable=1;
  553.     accessfile(tmplbuf,"r","/proc/net/tcp");
  554.     snprintf(tester,sizeof(tester)," 0100007F:%04X 0100007F:%04X ",
  555.            port,port2);
  556.     p=strstr(tmplbuf,tester);
  557.     if(p!=NULL) {
  558.       pp=strchr(p,'\n'); if(pp!=NULL) *pp=0;
  559.       if(strlen(p)>=75) {
  560.         p=find_word_start(p+70); *find_word_end(p)=0;
  561.         if(atoi(p)==geteuid()) manageable=2;
  562.       }
  563.     }
  564.   }
  565.   else manageable=1;
  566.   i=stat(config_file,&confstat);
  567.   if(i==0 && manageable>0 && (confstat.st_mode&(S_IRWXO|S_IRWXG))!=0) manageable=-1;
  568.   if(manageable>0 && !trusted_module()) manageable=0;
  569.   if(manageable==1) {
  570.     accessfile(tmplbuf,"r","%s/.manager",session_prefix);
  571.     if(strstr(tmplbuf,"yes")!=NULL) manageable=2;
  572.   }
  573.   if(manageable==1) {
  574.     p=getvar(ro_name[ro_module]);
  575.     if(p!=NULL && strncmp(p,"adm/manage",strlen("adm/manage"))==0) {
  576.       struct stat pstat;
  577.       if(stat("../log/.wimspass",&pstat)==0) {
  578.         if((S_IFMT&pstat.st_mode)!=S_IFREG ||
  579.            ((S_IRWXO|S_IRWXG)&pstat.st_mode)!=0)
  580.           manageable=-2;
  581.       }
  582.     }
  583.   }
  584.   mend:
  585.   mystrncpy(buf,int2str(manageable),sizeof(buf));
  586.   force_setvar("wims_ismanager",buf);
  587.   if(manageable>=2) {
  588.     struct rlimit rlim;
  589.     rlimit_cpu*=10;
  590.     rlim.rlim_cur=rlim.rlim_max=rlimit_cpu;
  591.     setrlimit(RLIMIT_CPU,&rlim);
  592.     mystrncpy(buf,int2str(rlimit_cpu),sizeof(buf));
  593.     setvar("wims_cpu_limit",buf);
  594.     initalarm();
  595.   }
  596. }
  597.  
  598. /* check for robot access */
  599. void robot_check(void)
  600. {
  601.   char *ua, *p, *ses, *c, *mod;
  602.   int i;
  603.  
  604.   if(human_access) return;
  605.   mod=getvar(ro_name[ro_module]);
  606.   if(mod!=NULL && strcmp(mod,"adm/raw")==0) return;
  607.   ses=getvar(ro_name[ro_session]);
  608. /* user has valid session; OK */
  609.   if(ses!=NULL && strncmp(ses,robot_session,strlen(robot_session))!=0
  610.      && strchr(ses,'/')==NULL
  611.      && ftest(mkfname(NULL,"%s/%s",s2_dir,ses))==is_dir)
  612.     return;
  613.   ua=getenv("HTTP_USER_AGENT"); if(ua==NULL) ua="";
  614.   ua=find_word_start(ua);
  615.   if(strncasecmp(ua,"Mozilla",strlen("Mozilla"))==0 &&
  616.      (p=strstr(ua,"compatible"))!=NULL)
  617.     ua=find_word_start(find_word_end(p));
  618.   if(*ua) {
  619.     for(i=0;i<good_agent_no
  620.         && strncasecmp(ua,good_agent[i],strlen(good_agent[i]));i++);
  621.     if(i<good_agent_no) return;
  622.     for(i=0;i<bad_agent_no
  623.         && strstr(ua,bad_agent[i])==NULL;i++);
  624.     if(i<bad_agent_no) user_error("trapped");
  625.   }
  626.   force_setvar(ro_name[ro_session],robot_session);
  627.   setsesdir(robot_session);
  628.   c=getvar(ro_name[ro_cmd]);
  629.   robot_access=1;
  630.   if(c!=NULL && strcmp(c,"new") && strcmp(c,"intro")) {
  631.     force_setvar(ro_name[ro_cmd],"robot_error");
  632.     nph_header(450); put_special_page("robot");
  633.     flushoutput(); flushlog(); exit(0);
  634.   }
  635. }
  636.  
  637. /* type=0: ordinary; type=1: multipart/form-data */
  638. void parse_query_string(int len, int type)
  639. {
  640.   int i,j,l,v,cmd_defined;
  641.   int parenth=-1, ll, lb, dlen;
  642.   char *start, *p, *p1, *pt, *b1="";
  643.  
  644.   cmd_defined=0;
  645.   setvar("wims_subsession","");
  646.   ll=lb=0;
  647.   if(type) {
  648.     ll=strlen(mpboundary);
  649.     start=strstr(var_str,mpboundary);
  650.     if(start==NULL) start=var_str+strlen(var_str);
  651.     if(strstr(var_str,"\r\n\r\n")!=NULL) b1="\r\n\r\n";
  652.     else b1="\n\n";
  653.     lb=strlen(b1);
  654.   }
  655.   else start=var_str;
  656.   for(v=0, p1=start;p1<var_str+len;p1+=l) {
  657.     if(type) {
  658.       char *p2, *p3, *p4, *p5;
  659.       p2=p1+ll; p3=memstr(p2,mpboundary,var_str+len-p2); l=p3-p1;
  660.       p=memstr(p2,b1,var_str+len-p2); if(p>=p3) continue;
  661.       p+=lb;
  662.       if(p3<var_str+len) {
  663.         while(*p3!='\n' && p3>p2) p3--;
  664.         *p3=0;
  665.         p3--; if(*p3=='\r') *p3=0;
  666.       }
  667.       dlen=p3-p;
  668.       p2=memstr(p2,"name=",p3-p2); if(p2>=p3) continue;
  669.       p2+=strlen("name="); if(*p2=='"') p2++;
  670.       for(p3=p2; myisalnum(*p3) || strchr("._",*p3)!=NULL; p3++);
  671.       if(p3==p2) continue;
  672.         if(p3-p2==strlen("wims_deposit") &&
  673.            strncmp(p2,"wims_deposit",p3-p2)==0) {
  674.           p4=memstr(p1,"filename=",p-p1); if(p4<p) {
  675.             p4+=strlen("filename="); if(*p4=='"') {
  676.               p4++; p5=strchr(p4,'"');
  677.               if(p5==NULL || p5-p4>=MAX_FNAME) goto emptyquote;
  678.             }
  679.             else {
  680.               emptyquote:
  681.               for(p5=p4; p5<p && !isspace(*p5) &&
  682.                   strchr(";\"~#*?=,'",*p5)==NULL; p5++);
  683.             }
  684.             if(p5>p4) {
  685.               *p5=0;
  686.               for(p5--;
  687.                   p5>=p4 && !isspace(*p5) && strchr("/\\:",*p5)==NULL;
  688.                   p5--);
  689.               if(p5>=p4) p4=p5+1;
  690.               if(*p4==0) goto noname;
  691.               if(strstr(p4,"..")!=NULL || *p4=='.')
  692.                 p4="noname.file";
  693.               setvar("wims_deposit",p4);
  694.             }
  695.             else {
  696.               noname: setvar("wims_deposit","noname.file");
  697.             }
  698.           }
  699.           deplen=dlen;
  700.         }
  701.         *p3=0; l-=p2-p1; p1=p2;
  702.     }
  703.     else {
  704.       p1=find_word_start(p1);
  705.       l=strlen(p1)+1; p=strchr(p1,'=');
  706.       if(p==NULL) p=p1+strlen(p1);
  707.       if(*p==0 && l>1) {
  708.         user_variable[v].name="no_name";
  709.         user_variable[v].value=p1;
  710.         coord_input=1;
  711.         goto nnext;
  712.       }
  713.       *p++=0;
  714.     }
  715. /* empty name or empty value: ignore */
  716.     if(*p1==0 || *p==0) continue;
  717. /* We do not treat names containing '.' */
  718.     for(pt=strchr(p1,'.'); pt; pt=strchr(++pt,'.')) *pt='_';
  719. /* Restrictions on variable names */
  720.     for(pt=p1; myisalnum(*pt) || *pt=='_'; pt++);
  721.     if(*pt) continue;
  722.     if(strcmp(p1,"wims_deposit")!=0) _tolinux(p);
  723. /* This is a restriction:
  724.  * Every parameter must have matching parentheses.
  725.  */
  726.     if(parenth==-1 && strncmp(p1,"freepar_",strlen("freepar_"))!=0
  727.          && strcmp(p1,"wims_deposit")!=0
  728.          && check_parentheses(p,1)) parenth=v;
  729.     if(strcmp(p1,"special_parm")==0 && strcmp(p,"wims")==0)
  730.         human_access=1;
  731.     j=search_list(ro_name,RO_NAME_NO,sizeof(ro_name[0]),p1);
  732.     if(j>=0) {
  733.       if(j==ro_session) {
  734.         p=find_word_start(p); *find_word_end(p)=0;
  735.         if(strlen(p)>MAX_SESSIONLEN) continue;
  736.         if(strcmp(p,robot_session)==0) p="";
  737.         if(strcasecmp(p,"popup")==0) {
  738.           mode=mode_popup;
  739.           force_setvar("wims_mode","popup");
  740.           force_setvar("session","");
  741.           continue;
  742.         }
  743.       }
  744.       if(j==ro_module) module_defined=1;
  745.       if(j==ro_cmd) {
  746.         p=find_word_start(p); *find_word_end(p)=0;
  747.         if(strlen(p)>16) continue;
  748.         cmd_defined=1;
  749.       }
  750.       if(j==ro_lang) {
  751.         if(strlen(p)!=2) continue;
  752.         for(i=0;i<available_lang_no && strcmp(available_lang[i],p)!=0;i++);
  753.         if(i<available_lang_no) {user_lang=1; ovlstrcpy(lang,p);}
  754.         else continue;
  755.       }
  756. /* strip leading and trailing '/'s in module name */
  757.       if(j==ro_module) {
  758.         p=find_word_start(p); *find_word_end(p)=0;
  759.         while(*p=='/') p++;
  760.         while(*p!=0 && *(p+strlen(p)-1)=='/') *(p+strlen(p)-1)=0;
  761.         if(strlen(p)>MAX_MODULELEN) continue;
  762.       }
  763.       setvar(p1,p);
  764.       if(j==ro_session && mode!=mode_popup) {
  765.         char *pp, *pr;
  766.         char buf[1024];
  767.         mystrncpy(buf,p,sizeof(buf));
  768.         if((pp=strchr(buf,'.'))!=NULL) {
  769.           *pp++=0; session_serial=atoi(pp);
  770.           if(pp<0) pp=0;
  771.         }
  772.         else session_serial=0;
  773.         pp=strchr(buf,'_');
  774.         if(pp!=NULL && (pr=strstr(pp,"_mhelp"))!=NULL) {
  775.           *pr=0; ismhelp=1; lastout_file=-1;
  776.           setvar("wims_inssub","mh");
  777.         }
  778.         force_setvar("wims_session",buf);
  779.         if(pp!=NULL) force_setvar("wims_subsession",pp);
  780.       }
  781.       continue;
  782.     }
  783.     user_variable[v].name=p1;
  784.     user_variable[v].value=p;
  785. nnext:v++; if(v>=MAX_VAR_NUM) user_error("too_many_variables");
  786.   }
  787.   user_var_no=v;
  788.   if(parenth>=0) {
  789.     char buf[16];
  790.     mystrncpy(buf,int2str(user_var_no),sizeof(buf));
  791.     setvar("user_var_no",buf);
  792.     for(i=0;i<user_var_no;i++) {
  793.       snprintf(buf,sizeof(buf),"name%d",i);
  794.       setvar(buf,user_variable[i].name);
  795.       snprintf(buf,sizeof(buf),"value%d",i);
  796.       setvar(buf,user_variable[i].value);
  797.     }
  798.     mystrncpy(buf,int2str(parenth),sizeof(buf));
  799.     setvar("bad_parentheses",buf);
  800.     user_error("unmatched_parentheses");
  801.   }
  802.   p=getenv("SCRIPT_NAME");
  803.   if(p!=NULL && (p=strstr(p,"/getfile/"))!=NULL) {
  804.     p+=strlen("/getfile/");
  805.     force_setvar(ro_name[ro_cmd],commands[cmd_getfile]);
  806.     force_setvar("special_parm",p);
  807.     cmd_defined=1;
  808.   }
  809.   if(module_defined && !cmd_defined) setvar(ro_name[ro_cmd],commands[cmd_intro]);
  810.   robot_check(); cookie2session();
  811. }
  812.  
  813. /* parse special commands */
  814. void special_cmds(void)
  815. {
  816.   char *c, *p;
  817.   int i;
  818.   long int l=-1;
  819.  
  820.   c=getvar(ro_name[ro_cmd]);
  821.   if(c==NULL || *c==0) {  /* no module name nor command */
  822.     setvar(ro_name[ro_module],home_module);
  823.     setvar(ro_name[ro_cmd],commands[cmd_new]);
  824.     return;
  825.   }
  826.   for(i=0;i<CMD_NO && strcmp(commands[i],c)!=0; i++);
  827.   switch(i) {
  828.     case cmd_intro: {
  829.       set_module_prefix();
  830.       default_form_method="get";
  831.       if(ftest(mkfname(NULL,"%s/%s",module_prefix,intro_file))<0) {
  832.         force_setvar(ro_name[ro_cmd],commands[cmd_new]);
  833.         return;
  834.       }
  835.       p=getvar("wims_session");
  836.       if(p!=NULL && *p!=0) {
  837.         if(set_session_prefix()==0) check_session();
  838.         else {
  839.           trap_check(p);
  840.           if(strchr(p,'_')!=NULL && strchr(p,'/')==NULL) {
  841.             get_static_session_var();
  842.           }
  843.         }
  844.       }
  845. /* determine http protocol name. How to detect? */
  846.       p=getenv("HTTPS");
  847.       if(p!=NULL && strcmp(p,"on")==0) {
  848.         protocol="https"; set_protocol();
  849.       }
  850.       force_setvar("wims_protocol",protocol);
  851.       determine_font(lang);
  852.       determine_dirn(lang);
  853.       main_phtml_put(intro_file); debug_output();
  854.       introend: write_logs();free(var_str);
  855.       delete_pid(); exit(0);
  856.     }
  857.     case cmd_ref: {
  858.       set_module_prefix();
  859.       default_form_method="get";
  860.       p=getvar("wims_session");
  861.       if(p!=NULL && *p!=0) {
  862.         if(set_session_prefix()==0) check_session();
  863.         else trap_check(p);
  864.       }
  865.       determine_font(lang);
  866.       determine_dirn(lang);
  867.       main_phtml_put(ref_file); goto introend;
  868.     }
  869.     case cmd_getins: {
  870.       c=getvar(ro_name[ro_special_parm]);
  871.       if(c==NULL || *c==0) {
  872.         user_error_nolog=1; user_error("no_insnum");
  873.       }
  874.       if(*c=='/' || strstr(c,"..")!=NULL) goto badins;
  875.       set_session_prefix();
  876.       if(strstr(session_prefix,"robot")!=NULL) exit(0);
  877.       l=filelength("%s/%s",s2_prefix,c);
  878.       if(l<0) {
  879.         badins: user_error_nolog=1; user_error("bad_insnum");
  880.       }
  881.       {
  882.         char *fmt;
  883.         fmt=strchr(c,'.');
  884.         if(fmt==NULL) {
  885.             user_error_nolog=1; user_error("bad_insnum");
  886.         }
  887.         else fmt++;
  888.  
  889.         nph_header(200);
  890. /* insert format problem; bricolage */
  891.         printf("Content-type: image/%s\r\n\
  892. Content-length: %ld\r\n\r\n",fmt,l);
  893.         catfile(stdout,"%s/%s",s2_prefix,c); exit(0);
  894.       }
  895.     }
  896.     case cmd_getfile: {
  897.       char fname[MAX_FNAME+1];
  898.       c=getvar(ro_name[ro_special_parm]);
  899.       if(c==NULL || *c==0) {
  900.         user_error_nolog=1; user_error("no_insnum");
  901.       }
  902.       if(*c=='/' || strstr(c,"..")!=NULL) goto badfile;
  903.  
  904.       set_session_prefix();
  905.       if(strstr(session_prefix,"robot")!=NULL) exit(0);
  906.       mkfname(fname,"%s/getfile/%s",session_prefix,c);
  907.       l=filelength("%s",fname);
  908.       if(l<0 && strchr(session_prefix,'_')!=NULL) {
  909.         char *pt;
  910.         mystrncpy(fname,session_prefix,sizeof(fname));
  911.         pt=strrchr(fname,'_'); if(pt) *pt=0;
  912.         snprintf(fname+(pt-fname),sizeof(fname)-(pt-fname),
  913.               "/getfile/%s",c);
  914.         l=filelength("%s",fname);
  915.       }
  916.       if(l<0) {
  917.         badfile: user_error_nolog=1; user_error("bad_insnum");
  918.       }
  919.       if(l>512*1024) {
  920.         struct rlimit rlim;
  921.         rlimit_cpu*=l/(10*1024);
  922.         rlim.rlim_cur=rlim.rlim_max=rlimit_cpu;
  923.           initalarm();
  924.       }
  925.       {
  926.         char *p1;
  927.         char mime[MAX_LINELEN+1];
  928.         for(p1=c+strlen(c);p1>c && isalpha(*(p1-1)); p1--);
  929.         ovlstrcpy(mime,"application/octet-stream");
  930.         if(p1>c && *(p1-1)=='.') {
  931.           setvar("translator_unknown",mime);
  932.           setvar("dictionary","bases/sys/mime");
  933.           snprintf(mime,sizeof(mime),"translator %s",p1);
  934.           calc_exec(mime);
  935.         }
  936.         nph_header(200);
  937.         printf("Content-type: %s\r\n\
  938. Content-length: %ld\r\n\r\n",mime,l);
  939.         catfile(stdout,"%s",fname); exit(0);
  940.       }
  941.     }
  942.     case cmd_close: {
  943.       char *p, b2[32]; int w;
  944.       char nbuf[MAX_FNAME+1], vbuf[MAX_LINELEN+1];
  945.       p=getvar(ro_name[ro_session]);
  946.       if(p==NULL || strlen(p)<10 ||
  947.          strchr(p,'/')!=NULL) return;
  948.       mystrncpy(b2,p,sizeof(b2));
  949.       p=strchr(b2,'.'); if(p!=NULL) *p=0;
  950.       mkfname(nbuf,"%s/%s/var.stat",session_dir,b2);
  951.       getdef(nbuf,"wims_caller",vbuf);
  952.       if(vbuf[0]!=0) force_setvar(ro_name[ro_session],vbuf);
  953.       w=wrapexec; wrapexec=1;
  954.       call_sh("rm -Rf %s/%s* %s/%s* >/dev/null 2>&1",session_dir,b2,s2_dir,b2);
  955.       wrapexec=w; cookiegot[0]=0;
  956.       force_setvar(ro_name[ro_cmd],"new");
  957.     }
  958.     default: return;
  959.   }
  960. }
  961.  
  962. /* This is run only when manually invoking the program.
  963.  * Verifies the orderedness of various list tables.
  964.  */
  965. int verify_tables(void)
  966. {
  967.     if(verify_order(calc_routine,CALC_FN_NO,sizeof(calc_routine[0]))) return -1;
  968.     if(verify_order(exec_routine,EXEC_FN_NO,sizeof(exec_routine[0]))) return -1;
  969.     if(verify_order(main_config,MAIN_CONFIG_NO,sizeof(main_config[0]))) return -1;
  970.     if(verify_order(mathname,mathname_no,sizeof(mathname[0]))) return -1;
  971.     if(verify_order(hmname,hmname_no,sizeof(hmname[0]))) return -1;
  972.     if(verify_order(ro_name,RO_NAME_NO,sizeof(ro_name[0]))) return -1;
  973.     if(verify_order(distr_cmd,distr_cmd_no,sizeof(distr_cmd[0]))) return -1;
  974.     if(verify_order(internal_name,INTERNAL_NAME_NO,
  975.                 sizeof(internal_name[0]))) return -1;
  976.     if(verify_order(tmathfn,tmathfn_no,sizeof(tmathfn[0]))) return -1;
  977.     if(verify_order(tmathvar,tmathvar_no,sizeof(tmathvar[0]))) return -1;
  978.     if(verify_order(modindex,MODINDEX_NO,sizeof(modindex[0]))) return -1;
  979.     if(verify_order(exportvars,exportvarcnt,sizeof(exportvars[0]))) return -1;
  980.     if(evaltab_verify()) return -1;
  981.     if(textab_verify()) return -1;
  982.     return 0;
  983. }
  984.  
  985. void config_defaults(void)
  986. {
  987.     int i;
  988.     for(i=0;i<MAIN_CONFIG_NO;i++) {
  989.       if((1&main_config[i].is_integer)==1) {
  990.           int *pi = (int*)main_config[i].address;
  991.           printf("DF_%s=%d\n",main_config[i].name, *pi);
  992.         }
  993.       else {
  994.             char **ps = (char**)main_config[i].address;
  995.           printf("DF_%s=%s\n",main_config[i].name,*ps);
  996.         }
  997.     }
  998. }
  999.  
  1000. /* get and set useroptions */
  1001. void useropts(void)
  1002. {
  1003.     char *p;
  1004.     setvar("lang",lang);
  1005.     p=getvar("useropts");
  1006.     if(p==NULL || *p==0) p=getvar("wims_useropts");
  1007.     if(p!=NULL && *p!=0) {
  1008.       if(myisdigit(p[0])) {
  1009.         usertexsize=p[0]-'0';
  1010.         /* fourth digit is for special fonts*/
  1011.         if(p[1]!=0) { mathalign_base=p[1]-'0'; }
  1012.       }
  1013.       if(myisdigit(p[3]) && p[3]!=0){ spec_font=p[3]-'0';}
  1014.     }
  1015.     if(mathalign_base==1) {
  1016.         mathalign_sup1="<sup>"; mathalign_sup2="</sup>";
  1017.     } else mathalign_sup1=mathalign_sup2="";
  1018. }
  1019.  
  1020. /* popup module help */
  1021. void mhelp(void)
  1022. {
  1023.     char *p, buf[MAX_LINELEN+1];
  1024.     main_phtml_put(""); buf[0]=0;
  1025.     if(cmd_type!=cmd_help) {
  1026.       phtml_put_base("closemhelp.phtml",0);
  1027.     }
  1028.     else {
  1029.       phtml_put_base("mhelpheader.phtml",0);
  1030.       p=getvar("special_parm");
  1031.       if(p!=NULL && strcmp(p,"about")==0)
  1032.         phtml_put("about.phtml",0);
  1033.       else phtml_put("help.phtml",0);
  1034.       phtml_put_base("mhelptail.phtml",0);
  1035.       exec_tail(buf);
  1036.     }
  1037. }
  1038.  
  1039. #define READSTDIN_WINDOW 4096
  1040.  
  1041. void readstdin(int len)
  1042. {
  1043.     int ll, l1, lt, lr;
  1044.     int cpulim;
  1045.  
  1046.     cpulim=rlimit_cpu; rlimit_cpu=3;
  1047.     lr=len; l1=0;
  1048.     while(lr>0) {
  1049.       nowtime=time(0); initalarm();
  1050.       ll=lr; if(ll>READSTDIN_WINDOW) ll=READSTDIN_WINDOW;
  1051.       lt=fread(stdinbuf+l1,1,ll,stdin);
  1052.       if(lt!=ll) user_error("parm_too_long");
  1053.       lr-=ll; l1+=ll;
  1054.     }
  1055.     if(l1!=len) user_error("parm_too_long");
  1056.     stdinbuf[len]=0; rlimit_cpu=cpulim;
  1057. }
  1058.  
  1059. /* input: p=QUERY_STRING. output: parameter length. */
  1060. /* Netscape puts form content into /tmp. */
  1061. int formdata(char *p)
  1062. {
  1063.     char *pp;
  1064.     int inlen;
  1065.     char *ctype;
  1066.     inlen=0; ctype=getenv("CONTENT_TYPE");
  1067.     if(ctype==NULL || strstr(ctype,"multipart/form-data")==NULL
  1068.        || (p=strstr(ctype,"boundary="))==NULL) {
  1069.       bad: stdinbuf=""; return 0;
  1070.     }
  1071.     pp=getenv("CONTENT_LENGTH");
  1072.     if(pp==NULL) goto bad;
  1073.     inlen=atoi(pp); if(inlen<=10) goto bad;
  1074.     if(inlen>=MAX_DEPOSITLEN) user_error("parm_too_long");
  1075.     stdinbuf=xmalloc(inlen+1); readstdin(inlen);
  1076.     p+=strlen("boundary=");
  1077.     for(pp=p;myisalnum(*pp) || *pp=='-'; pp++);
  1078.     if(pp-p<sizeof(mpboundary)-2) {
  1079.       memmove(mpboundary,p,pp-p); mpboundary[pp-p]=0;
  1080.     }
  1081. /* empty data */
  1082.     if(strstr(stdinbuf,mpboundary)==NULL || strstr(stdinbuf,"name=")==NULL) {
  1083.       free(stdinbuf); goto bad;
  1084.     }
  1085.     form_access=1; post_log();
  1086.     return inlen;
  1087. }
  1088.  
  1089. /* get the content of POST */
  1090. void getpost(void)
  1091. {
  1092.     int ll;
  1093.     char *pp;
  1094.     pp=getenv("CONTENT_LENGTH");
  1095.     if(pp==NULL || (ll=atoi(pp))<=0) {
  1096.       stdinbuf=xmalloc(16); stdinbuf[0]=0;
  1097.     }
  1098.     else {
  1099.       if(ll>QUERY_STRING_LIMIT) user_error("parm_too_long");
  1100.       stdinbuf=xmalloc(ll+16); readstdin(ll);
  1101.       if(ll>0) {
  1102.           setenv("QUERY_STRING",stdinbuf,1);
  1103.           form_access=1; post_log();
  1104.       }
  1105.     }
  1106. }
  1107.  
  1108. void buffer_init(void)
  1109. {
  1110.     struct timeval tv;
  1111.  
  1112.     mcachecnt=readnest=0;
  1113.     mpboundary[0]=cookiegot[0]=cookieset[0]=cwdbuf[0]=0;
  1114.     rscore_class[0]=rscore_user[0]=multiexec_random[0]=0;
  1115.     lastftest[0]=0;
  1116.     lastdatafile[0]=0; lastdata=xmalloc(WORKFILE_LIMIT);
  1117.     outptr=outbuf;
  1118.     instex_src[0]=instex_fname[0]=module_prefix[0]=0;
  1119.     examlogf[0]=examlogd[0]=exam_sheetexo[0]=0;
  1120.     freeworklogf[0]=freeworklogd[0]=0;
  1121.     stdinbuf=NULL;
  1122.     mkfname(tmp_dir,"../tmp/forall");
  1123.     mkfname(session_dir,"../%s",SESSION_BASE);
  1124.     mkfname(s2_dir,"../%s",S2_BASE);
  1125.     if(gettimeofday(&tv,NULL)) startmtime=startmtime2=0;
  1126.     else {
  1127.       startmtime=((tv.tv_sec%10000)*1000+tv.tv_usec/1000);
  1128.       startmtime2=(tv.tv_sec%1000)*1000000+tv.tv_usec;
  1129.     }
  1130. }
  1131.  
  1132. /**
  1133.  * runs the test suite, to check whether the documented commands of modtool
  1134.  * behave properly.
  1135.  * @param prefix path to the proc file to process
  1136.  * @param p      name of the proc file to proceed
  1137.  * @param vars a list of var names to print.
  1138.  **/
  1139. void test_suite(char *prefix, char *p, char *vars){
  1140.   char *v, *nextv;
  1141.   mystrncpy(module_prefix, prefix, sizeof(module_prefix));
  1142.   exec_read(p);
  1143.   nextv=vars;
  1144.   while (*nextv!='\0'){
  1145.     v=find_word_start(nextv);
  1146.     nextv=find_word_end(v);
  1147.     if (*nextv != '\0'){
  1148.       *nextv++='\0';
  1149.     }
  1150.     v=getvar(v);
  1151.     if(v) puts(v); else putchar('\n');
  1152.   }
  1153. }
  1154.  
  1155. int main(int argc, char *argv[], char *envp[])
  1156. {
  1157.     char *p, homebuf[MAX_FNAME+1], lbuf[32], buf[64];
  1158.     int inlen=0;
  1159. /*    int mfd; */
  1160.  
  1161.     class_dir[0]=0;
  1162.     substitute=substit; buffer_init(); var_init();
  1163. /* WIMS internal locale is always C. */
  1164.     setenv("LANG","C",1); umask(022);
  1165.     setenv("LANGUAGE","us",1);
  1166.     setenv("LC_ALL","C",1);
  1167.     if(argc>1) {
  1168.       if(strcasecmp(argv[1],"table")==0) {
  1169.           if(verify_tables()) internal_error("Table disorder.");
  1170.           else printf("Table orders OK.\n");
  1171.           return 0;
  1172.       }
  1173.       if(strcasecmp(argv[1],"version")==0) {
  1174.           printf("%s",wims_version); return 0;
  1175.       }
  1176.       if(strcasecmp(argv[1],"defaults")==0) {
  1177.           config_defaults(); return 0;
  1178.       }
  1179.       if(strcasecmp(argv[1],"test")==0) {
  1180. /* launches a test suite */
  1181.         if (argc < 5) {
  1182.           printf("Not enough arguments to launch a test; usage:\n");
  1183.           printf("wims test path_to_file name_of_proc_file 'var1 var2 ...'\n\n");
  1184.           printf("the file at path_to_file/name_of_proc_file will be evaluated by wims for\nexec commands, then the values of var1, var2, ... will be printed\nin the standard output, one per line.\n");
  1185.           return 1;
  1186.         }
  1187.         test_suite(argv[2], argv[3], argv[4]);
  1188.         return 0;
  1189.       }
  1190.     }
  1191.     p=getenv("SERVER_SOFTWARE"); if(p!=NULL && strcasecmp(p,"WIMS")==0)
  1192.       httpd_type=httpd_wims;
  1193.     p=getenv("REMOTE_ADDR"); if(p!=NULL) remote_addr=p;
  1194.     p=getenv("REMOTE_HOST"); if(p!=NULL) remote_host=p;
  1195.     nowtime=time(0); now=localtime(&nowtime);
  1196. /* nowtime contains the seconds elapsed from EPOCH (1970)
  1197.    but tm_year is set to current year-1900.
  1198.  */
  1199.     memmove(&Now, now, sizeof(Now)); now=&Now;
  1200.     snprintf(nowstr,sizeof(nowstr),"%04d%02d%02d.%02d:%02d:%02d",
  1201.            (now->tm_year)+1900,(now->tm_mon)+1,now->tm_mday,
  1202.            now->tm_hour,now->tm_min,now->tm_sec);
  1203.     p=getenv("QUERY_STRING");
  1204.     if(p==NULL || *p==0) getpost();
  1205.     else if(strncmp(p,"form-data",9)==0) inlen=formdata(p);
  1206.  
  1207.     force_setvar("wims_now",nowstr);
  1208.     snprintf(lbuf,sizeof(lbuf),"%lu",nowtime);
  1209.     force_setvar("wims_nowseconds",lbuf);
  1210.     nowtime=time(0);
  1211.     initalarm();
  1212.  
  1213.     executed_gotos=insert_no=output_length=0; ins_alt[0]=0;
  1214.     setvar("empty","");       /* lock this variable */
  1215.     setvar("wims_version",wims_version);
  1216.     setvar("wims_version_date",wims_version_date);
  1217.     setvar("wims_main_font","utf-8");
  1218.     take_httpd_vars();
  1219.  
  1220.     main_configure();
  1221.     checklogd();
  1222. /* mfd=shm_open(SHM_NAME,O_RDONLY,-1);
  1223.  * if(mfd==-1) internal_error("Unable to find shared memory.");
  1224.  * shmptr=mmap(0,SHM_SIZE,PROT_READ,MAP_SHARED,mfd,0);
  1225.  * if(shmptr==MAP_FAILED) internal_error("Shared memory failure.");
  1226.  */
  1227.     getppid(); /* this is the first sysmask trigger, must be after checklogd() */
  1228.     predetermine_language();
  1229.     /* modify a few rlimits for 64-bit processors */
  1230.     if (sizeof(long) == 8) {
  1231.       rlimit_as*=2;    /* virtual memory size */
  1232.       rlimit_data*=2;  /* data segment size; maxima requires a lot */
  1233.       rlimit_stack*=2; /* stack size */
  1234.     }
  1235.     set_rlimits();
  1236.     /*init_random();*/
  1237.     seed_time();
  1238.     p=getvar("wims_seed");
  1239.     mystrncpy(buf,p,sizeof(buf));
  1240.     exec_setseed(buf);
  1241.     module_configure();
  1242.     set_job_ident();
  1243.     m_file.name[0]=0;m_file.linecnt=m_file.linepointer=0;
  1244.     p=getenv("QUERY_STRING");
  1245.     if(p==NULL || strlen(p)==0) {
  1246.       setvar("lang",lang);
  1247.       snprintf(homebuf,sizeof(homebuf),"module=%s",home_module);
  1248.       p=homebuf;
  1249.     }
  1250.     if(strlen(p)>=QUERY_STRING_LIMIT) user_error("parm_too_long");
  1251.     if(mpboundary[0]==0) {
  1252.       var_str=xmalloc(strlen(p)+2);
  1253.       parse_query_string(http2env(var_str,p),0);
  1254.     }
  1255.     else {
  1256.       var_str=stdinbuf;
  1257.       parse_query_string(inlen,1);
  1258.     }
  1259.     if(ismhelp) {
  1260.       p=getvar(ro_name[ro_cmd]);
  1261.       if(p==NULL || (strcmp(p,"help")!=0 && strcmp(p,"getins")!=0)) {
  1262.           mhelp(); goto outgo;
  1263.       }
  1264.     }
  1265.     check_exam();
  1266.     useropts();
  1267.     special_cmds();
  1268.     parse_ro_names();
  1269.     manager_check();
  1270.     access_check(0);
  1271. /* it is really for developing in wims, so no use in general */
  1272.   if (1==1) {
  1273.     if(strstr(tmp_debug,"yes")!=NULL && checkhost(manager_site)>=1)
  1274.       trace_file = fopen(mkfname(NULL,"%s/%s",tmp_dir,"trace.txt"),"a");
  1275.   }
  1276.   set_variables();
  1277.   determine_font(getvar("module_language"));
  1278.   determine_dirn(getvar("module_language"));
  1279.   if(!robot_access && session_prefix[0]!=0 && cmd_type!=cmd_help && !ismhelp)
  1280.     lastout_file=creat(mkfname(NULL,"%s/%s",s2_prefix,lastout),
  1281.                  S_IRUSR|S_IWUSR);
  1282.   p=getvar("module_score");
  1283.   if(p!=NULL) force_setvar("wims_seed_score",p);
  1284.   p=getvar("module_category");
  1285.   if(p==NULL || strstr(p,"tool")==NULL) default_form_method="get";
  1286.   if(noout) {
  1287.     write_logs(); save_session_vars();
  1288.     goto outgo;
  1289.   }
  1290.   if(ismhelp) {
  1291.     mhelp();
  1292.   }
  1293.   else {
  1294.     main_phtml_put(html_file);
  1295.     if(lastout_file!=-1) {
  1296.       flushoutput(); close(lastout_file); putlastout();
  1297.     }
  1298.     write_logs(); save_session_vars();
  1299.   }
  1300.   outgo:
  1301.   debug_output();
  1302.   if (trace_file)  { fclose(trace_file); trace_file=NULL; }
  1303.   if(var_str!=stdinbuf) free(var_str);
  1304.   delete_pid();
  1305.   if(mode!=mode_popup && trusted_module()) {
  1306.     p=getvar("wims_mode");
  1307.     if(p!=NULL && strcmp(p,"popup")==0) mode=mode_popup;
  1308.   }
  1309.   if(mode==mode_popup && insert_no==0) {
  1310.     p=getvar("wims_mode");
  1311.     if(p!=NULL && strcmp(p,"popup")==0) {
  1312.       remove_tree(session_prefix);
  1313.  
  1314.       remove_tree(s2_prefix);
  1315.     }
  1316.   }
  1317.   return 0;
  1318. }
  1319.