1 /*************************************************************************************************
2  * CGI script for administration of database files
3  *                                                      Copyright (C) 2000-2003 Mikio Hirabayashi
4  * This file is part of QDBM, Quick Database Manager.
5  * QDBM is free software; you can redistribute it and/or modify it under the terms of the GNU
6  * Lesser General Public License as published by the Free Software Foundation; either version
7  * 2.1 of the License or any later version.  QDBM is distributed in the hope that it will be
8  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
10  * details.
11  * You should have received a copy of the GNU Lesser General Public License along with QDBM; if
12  * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
13  * 02111-1307 USA.
14  *************************************************************************************************/
15 
16 
17 #include <depot.h>
18 #include <curia.h>
19 #include <cabin.h>
20 #include <villa.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <time.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 
30 #undef TRUE
31 #define TRUE           1                 /* boolean true */
32 #undef FALSE
33 #define FALSE          0                 /* boolean false */
34 
35 #define CONFFILE    "qadm.conf"          /* name of the configuration file */
36 #define DEFENC      "US-ASCII"           /* default encoding */
37 #define DEFLANG     "en"                 /* default language */
38 #define DEFTITLE    "QDBM on WWW"        /* default title */
39 #define DEFDATADIR  "qadmdir"            /* directory containing database files */
40 #define RDATAMAX    262144               /* max size of data to read */
41 #define DBNAMEMAX   128                  /* max size of the name of a database */
42 #define PATHBUFSIZ  1024                 /* size of a buffer for path string */
43 #define TSTRBUFSIZ  256                  /* size of a buffer for time string */
44 
45 enum {
46   ACTNONE,
47   ACTDBDOWN,
48   ACTDBCREATE,
49   ACTDBREMOVE,
50   ACTRECLIST,
51   ACTRECPUTOVER,
52   ACTRECPUTKEEP,
53   ACTRECPUTCAT,
54   ACTRECPUTDUP,
55   ACTRECOUTONE,
56   ACTRECOUTLIST
57 };
58 
59 enum {
60   DBTDEPOT,
61   DBTCURIA,
62   DBTVILLA,
63   DBTERROR
64 };
65 
66 
67 /* global variables */
68 const char *scriptname;                  /* name of the script */
69 const char *enc;                         /* encoding of the page */
70 const char *lang;                        /* language of the page */
71 const char *title;                       /* title of the page */
72 int keychop;                             /* whether to chop keys */
73 int valchop;                             /* whether to chop values */
74 
75 
76 /* function prototypes */
77 int main(int argc, char **argv);
78 const char *skiplabel(const char *str);
79 CBMAP *getparams(void);
80 char *getpathinfo(void);
81 void senderror(int code, const char *tag, const char *message);
82 void dodbdown(const char *dbname);
83 void dorecdown(const char *dbname, const char *tkey);
84 void htmlprintf(const char *format, ...);
85 void printmime(void);
86 void printdecl(void);
87 void printhead(void);
88 const char *getdbattrs(const char *dbname, int *dbtp, int *rnump, int *fsizp, time_t *mtp);
89 const char *dbtstr(int dbt);
90 const char *timestr(time_t t);
91 void dodblist();
92 void dodbcreate(const char *dbname, int dbt);
93 void dodbremove(const char *dbname, int sure);
94 void doreclist(const char *dbname, int act, const char *key, const char *val, int sure);
95 void strchop(char *str);
96 void updatedepot(const char *dbname, int act, const char *key, const char *val);
97 void updatecuria(const char *dbname, int act, const char *key, const char *val);
98 void updatevilla(const char *dbname, int act, const char *key, const char *val);
99 void depotreclist(const char *dbname);
100 void curiareclist(const char *dbname);
101 void villareclist(const char *dbname);
102 
103 
104 /* main routine */
main(int argc,char ** argv)105 int main(int argc, char **argv){
106   CBMAP *params;
107   CBLIST *lines;
108   const char *tmp, *datadir, *dbname, *key, *val;
109   char *pinfo, *tkey;
110   int i, act, sure, dbt;
111   /* set configurations */
112   cbstdiobin();
113   scriptname = argv[0];
114   if((tmp = getenv("SCRIPT_NAME")) != NULL) scriptname = tmp;
115   enc = NULL;
116   lang = NULL;
117   title = NULL;
118   datadir = NULL;
119   keychop = FALSE;
120   valchop = FALSE;
121   if((lines = cbreadlines(CONFFILE)) != NULL){
122     for(i = 0; i < cblistnum(lines); i++){
123       tmp = cblistval(lines, i, NULL);
124       if(cbstrfwmatch(tmp, "encoding:")){
125         enc = skiplabel(tmp);
126       } else if(cbstrfwmatch(tmp, "lang:")){
127         lang = skiplabel(tmp);
128       } else if(cbstrfwmatch(tmp, "title:")){
129         title = skiplabel(tmp);
130       } else if(cbstrfwmatch(tmp, "datadir:")){
131         datadir = skiplabel(tmp);
132       } else if(cbstrfwmatch(tmp, "keychop:")){
133         if(!strcmp(skiplabel(tmp), "true")) keychop = TRUE;
134       } else if(cbstrfwmatch(tmp, "valchop:")){
135         if(!strcmp(skiplabel(tmp), "true")) valchop = TRUE;
136       }
137     }
138   }
139   if(!enc) enc = DEFENC;
140   if(!lang) lang = DEFLANG;
141   if(!title) title = DEFTITLE;
142   if(!datadir) datadir = DEFDATADIR;
143   /* read parameters */
144   dbname = NULL;
145   act = ACTNONE;
146   sure = FALSE;
147   dbt = DBTERROR;
148   key = NULL;
149   val = NULL;
150   params = getparams();
151   if((tmp = cbmapget(params, "act", -1, NULL)) != NULL) act = atoi(tmp);
152   if((tmp = cbmapget(params, "sure", -1, NULL)) != NULL) sure = atoi(tmp);
153   if((tmp = cbmapget(params, "dbname", -1, NULL)) != NULL) dbname = tmp;
154   if((tmp = cbmapget(params, "dbt", -1, NULL)) != NULL) dbt = atoi(tmp);
155   if((tmp = cbmapget(params, "key", -1, NULL)) != NULL) key = tmp;
156   if((tmp = cbmapget(params, "val", -1, NULL)) != NULL) val = tmp;
157   if(dbname && strlen(dbname) > DBNAMEMAX) dbname = NULL;
158   pinfo = getpathinfo();
159   /* show page or send data */
160   if(chdir(datadir) == -1){
161     senderror(500, "Internal Server Error", "Could not change the current directory.");
162   } else if(act == ACTDBDOWN){
163     dodbdown(dbname);
164   } else if(pinfo && (tkey = strchr(pinfo + 1, '/')) != NULL){
165     dbname = pinfo + 1;
166     *tkey = '\0';
167     tkey++;
168     dorecdown(dbname, tkey);
169   } else {
170     printmime();
171     printdecl();
172     htmlprintf("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"%s\" lang=\"%s\">\n",
173                lang, lang);
174     printhead();
175     htmlprintf("<body>\n");
176     if(act == ACTNONE){
177       htmlprintf("<h1>%@</h1>\n", title);
178     } else {
179       htmlprintf("<div class=\"note\"><a href=\"%s\">[BACK]</a></div>\n", scriptname);
180     }
181     htmlprintf("<hr />\n");
182     switch(act){
183     case ACTDBCREATE:
184       dodbcreate(dbname, dbt);
185       break;
186     case ACTDBREMOVE:
187       dodbremove(dbname, sure);
188       break;
189     case ACTRECLIST:
190     case ACTRECPUTOVER:
191     case ACTRECPUTKEEP:
192     case ACTRECPUTCAT:
193     case ACTRECPUTDUP:
194     case ACTRECOUTONE:
195     case ACTRECOUTLIST:
196       doreclist(dbname, act, key, val, sure);
197       break;
198     default:
199       dodblist();
200       break;
201     }
202     htmlprintf("<hr />\n");
203     if(act == ACTNONE)
204       htmlprintf("<div class=\"note\">Powered by QDBM %@.</div>\n", dpversion);
205     htmlprintf("</body>\n");
206     htmlprintf("</html>\n");
207   }
208   /* release resources */
209   cbmapclose(params);
210   if(lines) cblistclose(lines);
211   return 0;
212 }
213 
214 
215 /* skip the label of a line */
skiplabel(const char * str)216 const char *skiplabel(const char *str){
217   if(!(str = strchr(str, ':'))) return str;
218   str++;
219   while(*str != '\0' && (*str == ' ' || *str == '\t')){
220     str++;
221   }
222   return str;
223 }
224 
225 
226 /* get a map of the CGI parameters */
getparams(void)227 CBMAP *getparams(void){
228   CBMAP *params;
229   CBLIST *pairs;
230   char *rbuf, *buf, *key, *val, *dkey, *dval;
231   const char *tmp;
232   int i, len, c;
233   params = cbmapopen();
234   rbuf = NULL;
235   buf = NULL;
236   if((tmp = getenv("CONTENT_LENGTH")) != NULL && (len = atoi(tmp)) > 0 && len <= RDATAMAX){
237     rbuf = cbmalloc(len + 1);
238     for(i = 0; i < len && (c = getchar()) != EOF; i++){
239       rbuf[i] = c;
240     }
241     rbuf[i] = '\0';
242     if(i == len) buf = rbuf;
243   } else {
244     buf = getenv("QUERY_STRING");
245   }
246   if(buf != NULL){
247     buf = cbmemdup(buf, -1);
248     pairs = cbsplit(buf, -1, "&");
249     for(i = 0; i < cblistnum(pairs); i++){
250       key = cbmemdup(cblistval(pairs, i, NULL), -1);
251       if((val = strchr(key, '=')) != NULL){
252         *(val++) = '\0';
253         dkey = cburldecode(key, NULL);
254         dval = cburldecode(val, NULL);
255         cbmapput(params, dkey, -1, dval, -1, FALSE);
256         free(dval);
257         free(dkey);
258       }
259       free(key);
260     }
261     cblistclose(pairs);
262     free(buf);
263   }
264   free(rbuf);
265   return params;
266 }
267 
268 
269 /* get a string for PATH_INFO */
getpathinfo(void)270 char *getpathinfo(void){
271   const char *tmp;
272   if((tmp = getenv("PATH_INFO")) != NULL){
273     return cburldecode(tmp, NULL);
274   }
275   return NULL;
276 }
277 
278 
279 /* send error status */
senderror(int code,const char * tag,const char * message)280 void senderror(int code, const char *tag, const char *message){
281   printf("Status: %d %s\r\n", code, tag);
282   printf("Content-Type: text/plain; charset=US-ASCII\r\n");
283   printf("\r\n");
284   printf("%s\n", message);
285 }
286 
287 
288 /* send a database */
dodbdown(const char * dbname)289 void dodbdown(const char *dbname){
290   FILE *ifp;
291   int c;
292   if(!dbname || dbname[0] == '/' || strstr(dbname, "..") || !(ifp = fopen(dbname, "rb"))){
293     senderror(404, "File Not Found", "The database file was not found.");
294   } else {
295     printf("Content-Type: application/x-qdbm\r\n");
296     printf("\r\n");
297     while((c = fgetc(ifp)) != EOF){
298       putchar(c);
299     }
300     fclose(ifp);
301   }
302 }
303 
304 
305 /* send the value of a record */
dorecdown(const char * dbname,const char * tkey)306 void dorecdown(const char *dbname, const char *tkey){
307   char vlpath[PATHBUFSIZ], crpath[PATHBUFSIZ], dppath[PATHBUFSIZ], *vbuf;
308   int vsiz;
309   DEPOT *depot;
310   CURIA *curia;
311   VILLA *villa;
312   vbuf = NULL;
313   vsiz = 0;
314   sprintf(vlpath, "%s.vl", dbname);
315   sprintf(crpath, "%s.cr", dbname);
316   sprintf(dppath, "%s.dp", dbname);
317   if((villa = vlopen(vlpath, VL_OREADER, VL_CMPLEX)) != NULL){
318     vbuf = vlget(villa, tkey, -1, &vsiz);
319     vlclose(villa);
320   } else if((curia = cropen(crpath, CR_OREADER, -1, -1)) != NULL){
321     vbuf = crget(curia, tkey, -1, 0, -1, &vsiz);
322     crclose(curia);
323   } else if((depot = dpopen(dppath, DP_OREADER, -1)) != NULL){
324     vbuf = dpget(depot, tkey, -1, 0, -1, &vsiz);
325     dpclose(depot);
326   }
327   if(vbuf){
328     printf("Content-Type: text/plain; charset=%s\r\n", enc);
329     printf("Content-Length: %d\r\n", vsiz);
330     printf("\r\n");
331     printf("%s", vbuf);
332     free(vbuf);
333   } else {
334     senderror(404, "Record Not Found", "There is no corresponding record.");
335   }
336 }
337 
338 
339 /* HTML-oriented printf */
htmlprintf(const char * format,...)340 void htmlprintf(const char *format, ...){
341   va_list ap;
342   char *tmp;
343   unsigned char c;
344   va_start(ap, format);
345   while(*format != '\0'){
346     if(*format == '%'){
347       format++;
348       switch(*format){
349       case 's':
350         tmp = va_arg(ap, char *);
351         if(!tmp) tmp = "(null)";
352         printf("%s", tmp);
353         break;
354       case 'd':
355         printf("%d", va_arg(ap, int));
356         break;
357       case '@':
358         tmp = va_arg(ap, char *);
359         if(!tmp) tmp = "(null)";
360         while(*tmp){
361           switch(*tmp){
362           case '&': printf("&amp;"); break;
363           case '<': printf("&lt;"); break;
364           case '>': printf("&gt;"); break;
365           case '"': printf("&quot;"); break;
366           default: putchar(*tmp); break;
367           }
368           tmp++;
369         }
370         break;
371       case '?':
372         tmp = va_arg(ap, char *);
373         if(!tmp) tmp = "(null)";
374         while(*tmp){
375           c = *(unsigned char *)tmp;
376           if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
377              (c >= '0' && c <= '9') || (c != '\0' && strchr("_-.", c))){
378             putchar(c);
379           } else if(c == ' '){
380             putchar('+');
381           } else {
382             printf("%%%02X", c);
383           }
384           tmp++;
385         }
386         break;
387       case '%':
388         putchar('%');
389         break;
390       }
391     } else {
392       putchar(*format);
393     }
394     format++;
395   }
396   va_end(ap);
397 }
398 
399 
400 /* print mime headers */
printmime(void)401 void printmime(void){
402   printf("Content-Type: text/html; charset=%s\r\n", enc);
403   printf("Cache-Control: no-cache, must-revalidate\r\n");
404   printf("Pragma: no-cache\r\n");
405   printf("\r\n");
406   fflush(stdout);
407 }
408 
409 
410 /* print the declarations of XHTML */
printdecl(void)411 void printdecl(void){
412   htmlprintf("<?xml version=\"1.0\" encoding=\"%s\"?>\n", enc);
413   htmlprintf("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" "
414              "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
415 }
416 
417 
418 /* print headers */
printhead(void)419 void printhead(void){
420   htmlprintf("<head>\n");
421   htmlprintf("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\" />\n", enc);
422   htmlprintf("<meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />\n");
423   htmlprintf("<link rel=\"contents\" href=\"./\" />\n");
424   htmlprintf("<title>%@</title>\n", title);
425   htmlprintf("<style type=\"text/css\">\n");
426   htmlprintf("body { background-color: #eeeeee; color: #111111;"
427              " margin: 0em 0em; padding: 0em 1em; }\n");
428   htmlprintf(".note { margin: 0.5em 0.5em; text-align: right; }\n");
429   htmlprintf("h1,h2,p { margin: 0.5em 0.5em; }\n");
430   htmlprintf("hr { margin-top: 1.2em; margin-bottom: 0.8em; height: 1pt;");
431   htmlprintf(" color: #888888; background-color: #888888; border: none; }\n");
432   htmlprintf("a { color: #0022aa; text-decoration: none; }\n");
433   htmlprintf("a:hover { color: #1144ff; text-decoration: underline; }\n");
434   htmlprintf("a.head { color: #111111; text-decoration: none; }\n");
435   htmlprintf("em { font-weight: bold; font-style: normal; }\n");
436   htmlprintf("form { margin: 0em 0em; padding: 0em 0em; }\n");
437   htmlprintf("div,table { margin: 0em 1em; padding: 0em 0em;"
438              " border: none; border-collapse: collapse; }\n");
439   htmlprintf("th,td { margin: 0em 0em; padding: 0.2em 0.5em; vertical-align: top; }\n");
440   htmlprintf("th { font-size: smaller; font-weight: normal; text-align: left; }\n");
441   htmlprintf("td { background-color: #ddddee; border: solid 1pt #888888; }\n");
442   htmlprintf("td.str { text-align: left; }\n");
443   htmlprintf("td.num { text-align: right; }\n");
444   htmlprintf("td.raw { text-align: left; white-space: pre; font-family: monospace; }\n");
445   htmlprintf("</style>\n");
446   htmlprintf("</head>\n");
447 }
448 
449 
450 /* get the attributes of a database */
getdbattrs(const char * dbname,int * dbtp,int * rnump,int * fsizp,time_t * mtp)451 const char *getdbattrs(const char *dbname, int *dbtp, int *rnump, int *fsizp, time_t *mtp){
452   static char name[PATHBUFSIZ], *tmp;
453   DEPOT *depot;
454   CURIA *curia;
455   VILLA *villa;
456   struct stat sbuf;
457   strcpy(name, dbname);
458   *dbtp = DBTERROR;
459   *fsizp = -1;
460   *rnump = -1;
461   *mtp = -1;
462   if((tmp = strrchr(name, '.')) != NULL){
463     *tmp = '\0';
464     tmp++;
465     if(!strcmp(tmp, "dp")){
466       *dbtp = DBTDEPOT;
467     } else if(!strcmp(tmp, "cr")){
468       *dbtp = DBTCURIA;
469     } else if(!strcmp(tmp, "vl")){
470       *dbtp = DBTVILLA;
471     }
472   }
473   switch(*dbtp){
474   case DBTDEPOT:
475     if((depot = dpopen(dbname, DP_OREADER, -1)) != NULL){
476       *fsizp = dpfsiz(depot);
477       *rnump = dprnum(depot);
478       dpclose(depot);
479     }
480     break;
481   case DBTCURIA:
482     if((curia = cropen(dbname, CR_OREADER, -1, -1)) != NULL){
483       *fsizp = crfsiz(curia);
484       *rnump = crrnum(curia);
485       crclose(curia);
486     }
487     break;
488   case DBTVILLA:
489     if((villa = vlopen(dbname, VL_OREADER, VL_CMPLEX)) != NULL){
490       *fsizp = vlfsiz(villa);
491       *rnump = vlrnum(villa);
492       vlclose(villa);
493     }
494     break;
495   default:
496     break;
497   }
498   if(stat(dbname, &sbuf) == 0){
499     *mtp = sbuf.st_mtime;
500   }
501   return name;
502 }
503 
504 
505 /* get the string of a database type */
dbtstr(int dbt)506 const char *dbtstr(int dbt){
507   switch(dbt){
508   case DBTDEPOT: return "Depot";
509   case DBTCURIA: return "Curia";
510   case DBTVILLA: return "Villa";
511   default: break;
512   }
513   return "ERROR";
514 }
515 
516 
517 /* get the string of the time */
timestr(time_t t)518 const char *timestr(time_t t){
519   static char str[TSTRBUFSIZ];
520   struct tm *tsp;
521   tsp = localtime(&t);
522   sprintf(str, "%04d/%02d/%02d %02d:%02d:%02d",
523           tsp->tm_year + 1900, tsp->tm_mon + 1, tsp->tm_mday,
524           tsp->tm_hour, tsp->tm_min, tsp->tm_sec);
525   return str;
526 }
527 
528 
529 /* list existing databases */
dodblist()530 void dodblist(){
531   CBLIST *files;
532   const char *tmp, *name;
533   int i, dbt, rnum, fsiz;
534   time_t mt;
535   if(!(files = cbdirlist("."))){
536     htmlprintf("<p>The data directory could not be scanned.</p>\n");
537     return;
538   }
539   cblistsort(files);
540   htmlprintf("<p>The following are existing database files."
541              "  Select a database file and its action.</p>\n");
542   htmlprintf("<form action=\"%@\" method=\"post\">\n", scriptname);
543   htmlprintf("<table summary=\"databases\">\n");
544   htmlprintf("<tr>\n");
545   htmlprintf("<th abbr=\"name\">Name</th>\n");
546   htmlprintf("<th abbr=\"dbt\">Type of Database</th>\n");
547   htmlprintf("<th abbr=\"fsiz\">Size</th>\n");
548   htmlprintf("<th abbr=\"rnum\">Records</th>\n");
549   htmlprintf("<th abbr=\"last\">Last Modified</th>\n");
550   htmlprintf("<th abbr=\"acts\">Actions</th>\n");
551   htmlprintf("</tr>\n");
552   for(i = 0; i < cblistnum(files); i++){
553     tmp = cblistval(files, i, NULL);
554     if(!strcmp(tmp, ".") || !strcmp(tmp, "..")) continue;
555     name = getdbattrs(tmp, &dbt, &rnum, &fsiz, &mt);
556     htmlprintf("<tr>\n");
557     htmlprintf("<td class=\"str\"><em>%@</em></td>\n", name);
558     htmlprintf("<td class=\"str\">%@</td>\n", dbtstr(dbt));
559     htmlprintf("<td class=\"num\">%d</td>\n", fsiz);
560     htmlprintf("<td class=\"num\">%d</td>\n", rnum);
561     htmlprintf("<td class=\"str\">%s</td>\n", timestr(mt));
562     htmlprintf("<td class=\"str\">");
563     htmlprintf("<a href=\"%s?act=%d&amp;dbname=%?\">[OPEN]</a>",
564                scriptname, ACTRECLIST, tmp);
565     htmlprintf(" <a href=\"%s?act=%d&amp;dbname=%?&amp;sure=0\">[REMOVE]</a>",
566                scriptname, ACTDBREMOVE, tmp);
567     if(dbt != DBTCURIA){
568       htmlprintf(" <a href=\"%s?act=%d&amp;dbname=%?\">[D/L]</a>",
569                  scriptname, ACTDBDOWN, tmp);
570     }
571     htmlprintf("</td>\n");
572     htmlprintf("</tr>\n");
573   }
574   htmlprintf("</table>\n");
575   htmlprintf("</form>\n");
576   htmlprintf("<hr />\n");
577   htmlprintf("<p>This form is used in order to create a new database.</p>\n");
578   htmlprintf("<form action=\"%@\" method=\"post\">\n", scriptname);
579   htmlprintf("<table summary=\"new database\">\n");
580   htmlprintf("<tr>\n");
581   htmlprintf("<th abbr=\"name\">Name</th>\n");
582   htmlprintf("<th abbr=\"dbt\">Type of Database</th>\n");
583   htmlprintf("<th abbr=\"act\">Action</th>\n");
584   htmlprintf("</tr>\n");
585   htmlprintf("<tr>\n");
586   htmlprintf("<td class=\"str\">"
587              "<input type=\"text\" name=\"dbname\" size=\"32\" /></td>\n");
588   htmlprintf("<td class=\"str\"><select name=\"dbt\">\n");
589   htmlprintf("<option value=\"%d\">%@</option>\n", DBTDEPOT, dbtstr(DBTDEPOT));
590   htmlprintf("<option value=\"%d\">%@</option>\n", DBTCURIA, dbtstr(DBTCURIA));
591   htmlprintf("<option value=\"%d\">%@</option>\n", DBTVILLA, dbtstr(DBTVILLA));
592   htmlprintf("</select></td>\n");
593   htmlprintf("<td class=\"str\"><input type=\"submit\" value=\"Create\" /></td>\n");
594   htmlprintf("</tr>\n");
595   htmlprintf("</table>\n");
596   htmlprintf("<div><input type=\"hidden\" name=\"act\" value=\"%d\" /></div>\n", ACTDBCREATE);
597   htmlprintf("</form>\n");
598   cblistclose(files);
599 }
600 
601 
602 /* create a new database */
dodbcreate(const char * dbname,int dbt)603 void dodbcreate(const char *dbname, int dbt){
604   CBLIST *files;
605   char path[PATHBUFSIZ];
606   int i, err;
607   DEPOT *depot;
608   CURIA *curia;
609   VILLA *villa;
610   if(!dbname || strlen(dbname) < 1){
611     htmlprintf("<p>The name of the database is not defined.</p>\n");
612     return;
613   }
614   if(strchr(dbname, '/')){
615     htmlprintf("<p>The name of the database includes invalid characters: `/'.</p>\n");
616     return;
617   }
618   if(dbt == DBTERROR){
619     htmlprintf("<p>The parameters are invalid.</p>\n");
620     return;
621   }
622   if(!(files = cbdirlist("."))){
623     htmlprintf("<p>The data directory could not be scanned.</p>\n");
624     return;
625   }
626   for(i = 0; i < cblistnum(files); i++){
627     sprintf(path, "%s.dp", dbname);
628     if(cbstrfwmatch(cblistval(files, i, NULL), path)){
629       cblistclose(files);
630       htmlprintf("<p>`%@' is duplicated.</p>\n", dbname);
631       return;
632     }
633     sprintf(path, "%s.cr", dbname);
634     if(cbstrfwmatch(cblistval(files, i, NULL), path)){
635       cblistclose(files);
636       htmlprintf("<p>`%@' is duplicated.</p>\n", dbname);
637       return;
638     }
639     sprintf(path, "%s.vl", dbname);
640     if(cbstrfwmatch(cblistval(files, i, NULL), path)){
641       cblistclose(files);
642       htmlprintf("<p>`%@' is duplicated.</p>\n", dbname);
643       return;
644     }
645   }
646   cblistclose(files);
647   sprintf(path, "%s.%s", dbname, dbt == DBTDEPOT ? "dp" : dbt == DBTCURIA ? "cr" : "vl");
648   err = FALSE;
649   switch(dbt){
650   case DBTDEPOT:
651     if(!(depot = dpopen(path, DP_OWRITER | DP_OCREAT | DP_OTRUNC, -1)) ||
652        !dpclose(depot)) err = TRUE;
653     break;
654   case DBTCURIA:
655     if(!(curia = cropen(path, CR_OWRITER | CR_OCREAT | CR_OTRUNC, -1, -1)) ||
656        !crclose(curia)) err = TRUE;
657     break;
658   case DBTVILLA:
659     if(!(villa = vlopen(path, VL_OWRITER | VL_OCREAT | VL_OTRUNC, VL_CMPLEX)) ||
660        !vlclose(villa)) err = TRUE;
661     break;
662   }
663   if(err){
664     htmlprintf("<p>`%@' could not be created.</p>\n", dbname);
665   } else {
666     htmlprintf("<p>`<em>%@</em>' was created successfully.</p>\n", dbname);
667   }
668 }
669 
670 
671 /* remove a database */
dodbremove(const char * dbname,int sure)672 void dodbremove(const char *dbname, int sure){
673   const char *name;
674   int dbt, rnum, fsiz, err;
675   time_t mt;
676   if(!dbname || strlen(dbname) < 1){
677     htmlprintf("<p>The name of the database is not defined.</p>\n");
678     return;
679   }
680   name = getdbattrs(dbname, &dbt, &rnum, &fsiz, &mt);
681   if(!sure){
682     htmlprintf("<p>Do you really remove `<em>%@</em>'?</p>\n", name);
683     htmlprintf("<div><a href=\"%s?act=%d&amp;dbname=%?&amp;sure=1\">[REMOVE]</a></div>\n",
684                scriptname, ACTDBREMOVE, dbname);
685     return;
686   }
687   err = FALSE;
688   switch(dbt){
689   case DBTDEPOT:
690     if(!dpremove(dbname)) err = TRUE;
691     break;
692   case DBTCURIA:
693     if(!crremove(dbname)) err = TRUE;
694     break;
695   case DBTVILLA:
696     if(!vlremove(dbname)) err = TRUE;
697     break;
698   default:
699     err = TRUE;
700     break;
701   }
702   if(err){
703     htmlprintf("<p>`%@' could not be removed.</p>\n", name);
704   } else {
705     htmlprintf("<p>`<em>%@</em>' was removed successfully.</p>\n", name);
706   }
707 }
708 
709 
710 /* open a database */
doreclist(const char * dbname,int act,const char * key,const char * val,int sure)711 void doreclist(const char *dbname, int act, const char *key, const char *val, int sure){
712   const char *name;
713   int dbt, rnum, fsiz;
714   time_t mt;
715   if(!dbname || strlen(dbname) < 1){
716     htmlprintf("<p>The name of the database is not defined.</p>\n");
717     return;
718   }
719   if(strchr(dbname, '/')){
720     htmlprintf("<p>The name of the database includes invalid characters: `/'.</p>\n");
721     return;
722   }
723   name = getdbattrs(dbname, &dbt, &rnum, &fsiz, &mt);
724   switch(dbt){
725   case DBTDEPOT:
726     updatedepot(dbname, act, key, val);
727     break;
728   case DBTCURIA:
729     updatecuria(dbname, act, key, val);
730     break;
731   case DBTVILLA:
732     updatevilla(dbname, act, key, val);
733     break;
734   default:
735     htmlprintf("<p>The type of the database is invalid.</p>\n");
736     break;
737   }
738   name = getdbattrs(dbname, &dbt, &rnum, &fsiz, &mt);
739   htmlprintf("<table summary=\"attributes\">\n");
740   htmlprintf("<tr>\n");
741   htmlprintf("<th abbr=\"name\">Name</th>\n");
742   htmlprintf("<th abbr=\"dbt\">Type of Database</th>\n");
743   htmlprintf("<th abbr=\"fsiz\">Size</th>\n");
744   htmlprintf("<th abbr=\"rnum\">Records</th>\n");
745   htmlprintf("<th abbr=\"last\">Last Modified</th>\n");
746   htmlprintf("<th abbr=\"acts\">Actions</th>\n");
747   htmlprintf("</tr>\n");
748   htmlprintf("<tr>\n");
749   htmlprintf("<td class=\"str\"><em>%@</em></td>\n", name);
750   htmlprintf("<td class=\"str\">%s</td>\n", dbtstr(dbt));
751   htmlprintf("<td class=\"num\">%d</td>\n", fsiz);
752   htmlprintf("<td class=\"num\">%d</td>\n", rnum);
753   htmlprintf("<td class=\"str\">%s</td>\n", timestr(mt));
754   htmlprintf("<td class=\"str\">");
755   htmlprintf(" <a href=\"%s?act=%d&amp;dbname=%?&amp;sure=0\">[REMOVE]</a>",
756              scriptname, ACTDBREMOVE, dbname);
757   if(dbt != DBTCURIA){
758     htmlprintf(" <a href=\"%s?act=%d&amp;dbname=%?\">[D/L]</a>",
759                scriptname, ACTDBDOWN, dbname);
760   }
761   htmlprintf("</td>\n");
762   htmlprintf("</tr>\n");
763   htmlprintf("</table>\n");
764   htmlprintf("<hr />\n");
765   htmlprintf("<p>This form is used in order to update the database.</p>\n");
766   htmlprintf("<form action=\"%@\" method=\"post\">\n", scriptname);
767   htmlprintf("<table summary=\"update\">\n");
768   htmlprintf("<tr>\n");
769   htmlprintf("<th abbr=\"act\">Action:</th>\n");
770   htmlprintf("<td class=\"str\">\n");
771   htmlprintf("<select name=\"act\">\n");
772   htmlprintf("<option value=\"%d\"%s>PUT (over)</option>\n",
773              ACTRECPUTOVER, act == ACTRECPUTOVER ? " selected=\"selected\"" : "");
774   htmlprintf("<option value=\"%d\"%s>PUT (keep)</option>\n",
775              ACTRECPUTKEEP, act == ACTRECPUTKEEP ? " selected=\"selected\"" : "");
776   if(dbt == DBTVILLA){
777     htmlprintf("<option value=\"%d\"%s>PUT (dup)</option>\n",
778                ACTRECPUTDUP, act == ACTRECPUTDUP ? " selected=\"selected\"" : "");
779   } else {
780     htmlprintf("<option value=\"%d\"%s>PUT (cat)</option>\n",
781                ACTRECPUTCAT, act == ACTRECPUTCAT ? " selected=\"selected\"" : "");
782   }
783   if(dbt == DBTVILLA){
784     htmlprintf("<option value=\"%d\"%s>OUT (one)</option>\n",
785                ACTRECOUTONE, act == ACTRECOUTONE ? " selected=\"selected\"" : "");
786     htmlprintf("<option value=\"%d\"%s>OUT (list)</option>\n",
787                ACTRECOUTLIST, act == ACTRECOUTLIST ? " selected=\"selected\"" : "");
788   } else {
789     htmlprintf("<option value=\"%d\"%s>OUT</option>\n",
790                ACTRECOUTONE, act == ACTRECOUTONE ? " selected=\"selected\"" : "");
791   }
792   htmlprintf("</select>\n");
793   htmlprintf("<input type=\"submit\" value=\"Submit\" />\n");
794   htmlprintf("<input type=\"reset\" value=\"Reset\" />\n");
795   htmlprintf("</td>\n");
796   htmlprintf("</tr>\n");
797   htmlprintf("<tr>\n");
798   htmlprintf("<th abbr=\"key\">Key:</th>\n");
799   htmlprintf("<td class=\"str\">\n");
800   if(keychop){
801     htmlprintf("<input type=\"text\" name=\"key\" size=\"48\" />\n");
802   } else {
803     htmlprintf("<textarea name=\"key\" cols=\"48\" rows=\"3\"></textarea>\n");
804   }
805   htmlprintf("</td>\n");
806   htmlprintf("</tr>\n");
807   htmlprintf("<tr>\n");
808   htmlprintf("<th abbr=\"val\">Value:</th>\n");
809   htmlprintf("<td class=\"str\">\n");
810   if(valchop){
811     htmlprintf("<input type=\"text\" name=\"val\" size=\"48\" />\n");
812   } else {
813     htmlprintf("<textarea name=\"val\" cols=\"48\" rows=\"3\"></textarea>\n");
814   }
815   htmlprintf("</td>\n");
816   htmlprintf("</tr>\n");
817   htmlprintf("</table>\n");
818   htmlprintf("<div><input type=\"hidden\" name=\"dbname\" value=\"%@\" /></div>\n", dbname);
819   htmlprintf("<div><input type=\"hidden\" name=\"sure\" value=\"%d\" /></div>\n", sure);
820   htmlprintf("</form>\n");
821   htmlprintf("<hr />\n");
822   if(sure){
823     htmlprintf("<p>The following are all records of the database."
824                " : <a href=\"%s?act=%d&amp;dbname=%?&amp;sure=0\">"
825                "[HIDE RECORDS]</a></p>\n", scriptname, ACTRECLIST);
826     switch(dbt){
827     case DBTDEPOT: depotreclist(dbname); break;
828     case DBTCURIA: curiareclist(dbname); break;
829     case DBTVILLA: villareclist(dbname); break;
830     default: break;
831     }
832   } else {
833     htmlprintf("<p>The records are not shown now."
834                " : <a href=\"%s?act=%d&amp;dbname=%?&amp;sure=1\">"
835                "[SHOW RECORDS]</a></p>\n", scriptname, ACTRECLIST);
836   }
837 }
838 
839 
840 /* chop the string */
strchop(char * str)841 void strchop(char *str){
842   int i;
843   for(i = strlen(str) - 1; i >= 0; i--){
844     if(strchr(" \r\n\t", str[i])){
845       str[i] = '\0';
846     } else {
847       break;
848     }
849   }
850 }
851 
852 
853 /* update the database of Depot */
updatedepot(const char * dbname,int act,const char * key,const char * val)854 void updatedepot(const char *dbname, int act, const char *key, const char *val){
855   int put, dmode;
856   DEPOT *depot;
857   char *kbuf, *vbuf;
858   put = FALSE;
859   dmode = DP_DOVER;
860   switch(act){
861   case ACTRECPUTOVER:
862     put = TRUE;
863     dmode = DP_DOVER;
864     break;
865   case ACTRECPUTKEEP:
866     put = TRUE;
867     dmode = DP_DKEEP;
868     break;
869   case ACTRECPUTCAT:
870     put = TRUE;
871     dmode = DP_DCAT;
872     break;
873   case ACTRECOUTONE:
874     break;
875   default:
876     return;
877   }
878   if(!key || !val){
879     htmlprintf("<p>Parameters are lack to update the database.</p>\n");
880     htmlprintf("<hr />\n");
881     return;
882   }
883   if(!(depot = dpopen(dbname, DP_OWRITER, -1))){
884     htmlprintf("<p>The database file could not open as a writer.</p>\n");
885     htmlprintf("<hr />\n");
886     return;
887   }
888   if(put){
889     kbuf = cbmemdup(key, -1);
890     vbuf = cbmemdup(val, -1);
891     if(keychop) strchop(kbuf);
892     if(valchop) strchop(vbuf);
893     if(dpput(depot, kbuf, -1, vbuf, -1, dmode)){
894       htmlprintf("<p>A record was stored.</p>\n");
895     } else if(dpecode == DP_EKEEP){
896       htmlprintf("<p>An existing record are kept.</p>\n");
897     } else {
898       htmlprintf("<p>The database has a fatal error.</p>\n");
899     }
900     free(vbuf);
901     free(kbuf);
902   } else {
903     if(dpout(depot, key, -1)){
904       htmlprintf("<p>A record was deleted.</p>\n");
905     } else if(dpecode == DP_ENOITEM){
906       htmlprintf("<p>There is no such record.</p>\n");
907     } else {
908       htmlprintf("<p>The database has a fatal error.</p>\n");
909     }
910   }
911   if(!dpclose(depot)) htmlprintf("<p>The database has a fatal error.</p>\n");
912   htmlprintf("<hr />\n");
913 }
914 
915 
916 /* update the database of Curia */
updatecuria(const char * dbname,int act,const char * key,const char * val)917 void updatecuria(const char *dbname, int act, const char *key, const char *val){
918   int put, dmode;
919   CURIA *curia;
920   char *kbuf, *vbuf;
921   put = FALSE;
922   dmode = CR_DOVER;
923   switch(act){
924   case ACTRECPUTOVER:
925     put = TRUE;
926     dmode = CR_DOVER;
927     break;
928   case ACTRECPUTKEEP:
929     put = TRUE;
930     dmode = CR_DKEEP;
931     break;
932   case ACTRECPUTCAT:
933     put = TRUE;
934     dmode = CR_DCAT;
935     break;
936   case ACTRECOUTONE:
937     break;
938   default:
939     return;
940   }
941   if(!key || !val){
942     htmlprintf("<p>Parameters are lack to update the database.</p>\n");
943     htmlprintf("<hr />\n");
944     return;
945   }
946   if(!(curia = cropen(dbname, CR_OWRITER, -1, -1))){
947     htmlprintf("<p>The database file could not open as a writer.</p>\n");
948     htmlprintf("<hr />\n");
949     return;
950   }
951   if(put){
952     kbuf = cbmemdup(key, -1);
953     vbuf = cbmemdup(val, -1);
954     if(keychop) strchop(kbuf);
955     if(valchop) strchop(vbuf);
956     if(crput(curia, kbuf, -1, vbuf, -1, dmode)){
957       htmlprintf("<p>A record was stored.</p>\n");
958     } else if(dpecode == DP_EKEEP){
959       htmlprintf("<p>An existing record are kept.</p>\n");
960     } else {
961       htmlprintf("<p>The database has a fatal error.</p>\n");
962     }
963     free(vbuf);
964     free(kbuf);
965   } else {
966     if(crout(curia, key, -1)){
967       htmlprintf("<p>A record was deleted.</p>\n");
968     } else if(dpecode == DP_ENOITEM){
969       htmlprintf("<p>There is no such record.</p>\n");
970     } else {
971       htmlprintf("<p>The database has a fatal error.</p>\n");
972     }
973   }
974   if(!crclose(curia)) htmlprintf("<p>The database has a fatal error.</p>\n");
975   htmlprintf("<hr />\n");
976 }
977 
978 
979 /* update the database of Villa */
updatevilla(const char * dbname,int act,const char * key,const char * val)980 void updatevilla(const char *dbname, int act, const char *key, const char *val){
981   int put, dmode, olist;
982   VILLA *villa;
983   char *kbuf, *vbuf;
984   put = FALSE;
985   dmode = VL_DOVER;
986   olist = FALSE;
987   switch(act){
988   case ACTRECPUTOVER:
989     put = TRUE;
990     dmode = VL_DOVER;
991     break;
992   case ACTRECPUTKEEP:
993     put = TRUE;
994     dmode = VL_DKEEP;
995     break;
996   case ACTRECPUTDUP:
997     put = TRUE;
998     dmode = VL_DDUP;
999     break;
1000   case ACTRECOUTONE:
1001     olist = FALSE;
1002     break;
1003   case ACTRECOUTLIST:
1004     olist = TRUE;
1005     break;
1006   default:
1007     return;
1008   }
1009   if(!key || !val){
1010     htmlprintf("<p>Parameters are lack to update the database.</p>\n");
1011     htmlprintf("<hr />\n");
1012     return;
1013   }
1014   if(!(villa = vlopen(dbname, VL_OWRITER, VL_CMPLEX))){
1015     htmlprintf("<p>The database file could not open as a writer.</p>\n");
1016     htmlprintf("<hr />\n");
1017     return;
1018   }
1019   if(put){
1020     kbuf = cbmemdup(key, -1);
1021     vbuf = cbmemdup(val, -1);
1022     if(keychop) strchop(kbuf);
1023     if(valchop) strchop(vbuf);
1024     if(vlput(villa, kbuf, -1, vbuf, -1, dmode)){
1025       htmlprintf("<p>A record was stored.</p>\n");
1026     } else if(dpecode == DP_EKEEP){
1027       htmlprintf("<p>An existing record are kept.</p>\n");
1028     } else {
1029       htmlprintf("<p>The database has a fatal error.</p>\n");
1030     }
1031     free(vbuf);
1032     free(kbuf);
1033   } else {
1034     if(olist ? vloutlist(villa, key, -1) : vlout(villa, key, -1)){
1035       if(olist){
1036         htmlprintf("<p>Some records were deleted.</p>\n");
1037       } else {
1038         htmlprintf("<p>A record was deleted.</p>\n");
1039       }
1040     } else if(dpecode == DP_ENOITEM){
1041       htmlprintf("<p>There is no such record.</p>\n");
1042     } else {
1043       htmlprintf("<p>The database has a fatal error.</p>\n");
1044     }
1045   }
1046   if(!vlclose(villa)) htmlprintf("<p>The database has a fatal error.</p>\n");
1047   htmlprintf("<hr />\n");
1048 }
1049 
1050 
1051 /* list records of Depot */
depotreclist(const char * dbname)1052 void depotreclist(const char *dbname){
1053   DEPOT *depot;
1054   char *kbuf, *vbuf;
1055   int i, ksiz, vsiz;
1056   if(!(depot = dpopen(dbname, DP_OREADER, -1))){
1057     htmlprintf("<p>The database file could not open as a reader.</p>\n");
1058     return;
1059   }
1060   dpiterinit(depot);
1061   htmlprintf("<table summary=\"records\">\n");
1062   htmlprintf("<tr>\n");
1063   htmlprintf("<th abbr=\"number\">#</th>\n");
1064   htmlprintf("<th abbr=\"keys\">Keys</th>\n");
1065   htmlprintf("<th abbr=\"vals\">Values</th>\n");
1066   htmlprintf("</tr>\n");
1067   for(i = 1; (kbuf = dpiternext(depot, &ksiz)) != NULL; i++){
1068     if(!(vbuf = dpget(depot, kbuf, ksiz, 0, -1, &vsiz))){
1069       free(kbuf);
1070       continue;
1071     }
1072     htmlprintf("<tr>\n");
1073     htmlprintf("<td class=\"num\"><var>%d</var></td>\n", i);
1074     htmlprintf("<td class=\"raw\">%@</td>\n", kbuf);
1075     htmlprintf("<td class=\"raw\">%@</td>\n", vbuf);
1076     htmlprintf("</tr>\n");
1077     free(vbuf);
1078     free(kbuf);
1079   }
1080   htmlprintf("</table>\n");
1081   dpclose(depot);
1082 }
1083 
1084 
1085 /* list records of Curia */
curiareclist(const char * dbname)1086 void curiareclist(const char *dbname){
1087   CURIA *curia;
1088   char *kbuf, *vbuf;
1089   int i, ksiz, vsiz;
1090   if(!(curia = cropen(dbname, CR_OREADER, -1, -1))){
1091     htmlprintf("<p>The database file could not open as a reader.</p>\n");
1092     return;
1093   }
1094   criterinit(curia);
1095   htmlprintf("<table summary=\"records\">\n");
1096   htmlprintf("<tr>\n");
1097   htmlprintf("<th abbr=\"number\">#</th>\n");
1098   htmlprintf("<th abbr=\"keys\">Keys</th>\n");
1099   htmlprintf("<th abbr=\"vals\">Values</th>\n");
1100   htmlprintf("</tr>\n");
1101   for(i = 1; (kbuf = criternext(curia, &ksiz)) != NULL; i++){
1102     if(!(vbuf = crget(curia, kbuf, ksiz, 0, -1, &vsiz))){
1103       free(kbuf);
1104       continue;
1105     }
1106     htmlprintf("<tr>\n");
1107     htmlprintf("<td class=\"num\"><var>%d</var></td>\n", i);
1108     htmlprintf("<td class=\"raw\">%@</td>\n", kbuf);
1109     htmlprintf("<td class=\"raw\">%@</td>\n", vbuf);
1110     htmlprintf("</tr>\n");
1111     free(vbuf);
1112     free(kbuf);
1113   }
1114   htmlprintf("</table>\n");
1115   crclose(curia);
1116 }
1117 
1118 
1119 /* list records of Villa */
villareclist(const char * dbname)1120 void villareclist(const char *dbname){
1121   VILLA *villa;
1122   char *kbuf, *vbuf;
1123   int i, ksiz, vsiz;
1124   if(!(villa = vlopen(dbname, VL_OREADER, VL_CMPLEX))){
1125     htmlprintf("<p>The database file could not open as a reader.</p>\n");
1126     return;
1127   }
1128   vlcurfirst(villa);
1129   htmlprintf("<table summary=\"records\">\n");
1130   htmlprintf("<tr>\n");
1131   htmlprintf("<th abbr=\"number\">#</th>\n");
1132   htmlprintf("<th abbr=\"keys\">Keys</th>\n");
1133   htmlprintf("<th abbr=\"vals\">Values</th>\n");
1134   htmlprintf("</tr>\n");
1135   for(i = 1; (kbuf = vlcurkey(villa, &ksiz)) != NULL; i++){
1136     if(!(vbuf = vlcurval(villa, &vsiz))){
1137       free(kbuf);
1138       vlcurnext(villa);
1139       continue;
1140     }
1141     htmlprintf("<tr>\n");
1142     htmlprintf("<td class=\"num\"><var>%d</var></td>\n", i);
1143     htmlprintf("<td class=\"raw\">%@</td>\n", kbuf);
1144     htmlprintf("<td class=\"raw\">%@</td>\n", vbuf);
1145     htmlprintf("</tr>\n");
1146     free(vbuf);
1147     free(kbuf);
1148     vlcurnext(villa);
1149   }
1150   htmlprintf("</table>\n");
1151   vlclose(villa);
1152 }
1153 
1154 
1155 
1156 /* END OF FILE */
1157