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("&"); break;
363 case '<': printf("<"); break;
364 case '>': printf(">"); break;
365 case '"': printf("""); 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&dbname=%?\">[OPEN]</a>",
564 scriptname, ACTRECLIST, tmp);
565 htmlprintf(" <a href=\"%s?act=%d&dbname=%?&sure=0\">[REMOVE]</a>",
566 scriptname, ACTDBREMOVE, tmp);
567 if(dbt != DBTCURIA){
568 htmlprintf(" <a href=\"%s?act=%d&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&dbname=%?&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&dbname=%?&sure=0\">[REMOVE]</a>",
756 scriptname, ACTDBREMOVE, dbname);
757 if(dbt != DBTCURIA){
758 htmlprintf(" <a href=\"%s?act=%d&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&dbname=%?&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&dbname=%?&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