* Add CONF options for master user/pass
[citadel.git] / citadel / modules / vandelay / serv_vandelay.c
1 /*
2  * $Id$
3  *
4  * This is the "Art Vandelay" module.  It is an importer/exporter.
5  *
6  */
7
8 #include "sysdep.h"
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <signal.h>
14 #include <pwd.h>
15 #include <errno.h>
16 #include <sys/types.h>
17
18 #if TIME_WITH_SYS_TIME
19 # include <sys/time.h>
20 # include <time.h>
21 #else
22 # if HAVE_SYS_TIME_H
23 #  include <sys/time.h>
24 # else
25 #  include <time.h>
26 # endif
27 #endif
28
29 #include <sys/wait.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <limits.h>
33 #include "citadel.h"
34 #include "server.h"
35 #include "citserver.h"
36 #include "support.h"
37 #include "config.h"
38 #include "database.h"
39 #include "msgbase.h"
40 #include "tools.h"
41 #include "user_ops.h"
42 #include "room_ops.h"
43 #include "control.h"
44 #include "euidindex.h"
45
46
47 #include "ctdl_module.h"
48
49
50
51
52 #define END_OF_MESSAGE  "---eom---dbd---"
53
54 char artv_tempfilename1[PATH_MAX];
55 char artv_tempfilename2[PATH_MAX];
56 FILE *artv_global_message_list;
57
58 void artv_export_users_backend(struct ctdluser *buf, void *data) {
59         cprintf("user\n");
60 /*
61 #include "artv_serialize.h"
62 #include "dtds/user-defs.h"
63 #include "undef_data.h"
64 */
65         cprintf("%d\n", buf->version);
66         cprintf("%ld\n", (long)buf->uid);
67         cprintf("%s\n", buf->password);
68         cprintf("%u\n", buf->flags);
69         cprintf("%ld\n", buf->timescalled);
70         cprintf("%ld\n", buf->posted);
71         cprintf("%d\n", buf->axlevel);
72         cprintf("%ld\n", buf->usernum);
73         cprintf("%ld\n", (long)buf->lastcall);
74         cprintf("%d\n", buf->USuserpurge);
75         cprintf("%s\n", buf->fullname);
76         cprintf("%d\n", buf->USscreenwidth);
77         cprintf("%d\n", buf->USscreenheight);
78 }
79
80
81 void artv_export_users(void) {
82         ForEachUser(artv_export_users_backend, NULL);
83 }
84
85
86 void artv_export_room_msg(long msgnum, void *userdata) {
87         cprintf("%ld\n", msgnum);
88         fprintf(artv_global_message_list, "%ld\n", msgnum);
89 }
90
91
92 void artv_export_rooms_backend(struct ctdlroom *buf, void *data) {
93         cprintf("room\n");
94 /*
95 #include "artv_serialize.h"
96 #include "dtds/room-defs.h"
97 #include "undef_data.h"
98 */
99         cprintf("%s\n", buf->QRname);
100         cprintf("%s\n", buf->QRpasswd);
101         cprintf("%ld\n", buf->QRroomaide);
102         cprintf("%ld\n", buf->QRhighest);
103         cprintf("%ld\n", (long)buf->QRgen);
104         cprintf("%u\n", buf->QRflags);
105         cprintf("%s\n", buf->QRdirname);
106         cprintf("%ld\n", buf->QRinfo);
107         cprintf("%d\n", buf->QRfloor);
108         cprintf("%ld\n", (long)buf->QRmtime);
109         cprintf("%d\n", buf->QRep.expire_mode);
110         cprintf("%d\n", buf->QRep.expire_value);
111         cprintf("%ld\n", buf->QRnumber);
112         cprintf("%d\n", buf->QRorder);
113         cprintf("%u\n", buf->QRflags2);
114         cprintf("%d\n", buf->QRdefaultview);
115
116         getroom(&CC->room, buf->QRname);
117         /* format of message list export is all message numbers output
118          * one per line terminated by a 0.
119          */
120 //*/
121         getroom(&CC->room, buf->QRname);
122         /* format of message list export is all message numbers output
123          * one per line terminated by a 0.
124          */
125         CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL,
126                 artv_export_room_msg, NULL);
127         cprintf("0\n");
128
129 }
130
131
132
133 void artv_export_rooms(void) {
134         char cmd[SIZ];
135         artv_global_message_list = fopen(artv_tempfilename1, "w");
136         if (artv_global_message_list != NULL) {
137                 ForEachRoom(artv_export_rooms_backend, NULL);
138                 fclose(artv_global_message_list);
139         }
140
141         /*
142          * Process the 'global' message list.  (Sort it and remove dups.
143          * Dups are ok because a message may be in more than one room, but
144          * this will be handled by exporting the reference count, not by
145          * exporting the message multiple times.)
146          */
147         snprintf(cmd, sizeof cmd, "sort <%s >%s", artv_tempfilename1, artv_tempfilename2);
148         system(cmd);
149         snprintf(cmd, sizeof cmd, "uniq <%s >%s", artv_tempfilename2, artv_tempfilename1);
150         system(cmd);
151 }
152
153
154 void artv_export_floors(void) {
155         struct floor qfbuf, *buf;
156         int i;
157
158         for (i=0; i < MAXFLOORS; ++i) {
159                 cprintf("floor\n");
160                 cprintf("%d\n", i);
161                 getfloor(&qfbuf, i);
162                 buf = &qfbuf;
163 /*
164 #include "artv_serialize.h"
165 #include "dtds/floor-defs.h"
166 #include "undef_data.h"
167 /*/
168                 cprintf("%u\n", buf->f_flags);
169                 cprintf("%s\n", buf->f_name);
170                 cprintf("%d\n", buf->f_ref_count);
171                 cprintf("%d\n", buf->f_ep.expire_mode);
172                 cprintf("%d\n", buf->f_ep.expire_value);
173 //*/
174         }
175 }
176
177
178
179
180
181 /* 
182  *  Traverse the visits file...
183  */
184 void artv_export_visits(void) {
185         struct visit vbuf;
186         struct cdbdata *cdbv;
187
188         cdb_rewind(CDB_VISIT);
189
190         while (cdbv = cdb_next_item(CDB_VISIT), cdbv != NULL) {
191                 memset(&vbuf, 0, sizeof(struct visit));
192                 memcpy(&vbuf, cdbv->ptr,
193                        ((cdbv->len > sizeof(struct visit)) ?
194                         sizeof(struct visit) : cdbv->len));
195                 cdb_free(cdbv);
196
197                 cprintf("visit\n");
198                 cprintf("%ld\n", vbuf.v_roomnum);
199                 cprintf("%ld\n", vbuf.v_roomgen);
200                 cprintf("%ld\n", vbuf.v_usernum);
201
202                 if (!IsEmptyStr(vbuf.v_seen)) {
203                         cprintf("%s\n", vbuf.v_seen);
204                 }
205                 else {
206                         cprintf("%ld\n", vbuf.v_lastseen);
207                 }
208
209                 cprintf("%s\n", vbuf.v_answered);
210                 cprintf("%u\n", vbuf.v_flags);
211                 cprintf("%d\n", vbuf.v_view);
212         }
213 }
214
215
216 void artv_export_message(long msgnum) {
217         struct MetaData smi;
218         struct CtdlMessage *msg;
219         struct ser_ret smr;
220         FILE *fp;
221         char buf[SIZ];
222         char tempfile[PATH_MAX];
223
224         msg = CtdlFetchMessage(msgnum, 1);
225         if (msg == NULL) return;        /* fail silently */
226
227         cprintf("message\n");
228         GetMetaData(&smi, msgnum);
229         cprintf("%ld\n", msgnum);
230         cprintf("%d\n", smi.meta_refcount);
231         cprintf("%s\n", smi.meta_content_type);
232
233         serialize_message(&smr, msg);
234         CtdlFreeMessage(msg);
235
236         /* write it in base64 */
237         CtdlMakeTempFileName(tempfile, sizeof tempfile);
238         snprintf(buf, sizeof buf, "%s -e >%s", file_base64, tempfile);
239         fp = popen(buf, "w");
240         fwrite(smr.ser, smr.len, 1, fp);
241         pclose(fp);
242
243         free(smr.ser);
244
245         fp = fopen(tempfile, "r");
246         unlink(tempfile);
247         if (fp != NULL) {
248                 while (fgets(buf, sizeof(buf), fp) != NULL) {
249                         buf[strlen(buf)-1] = 0;
250                         cprintf("%s\n", buf);
251                 }
252                 fclose(fp);
253         }
254         cprintf("%s\n", END_OF_MESSAGE);
255 }
256
257
258
259 void artv_export_messages(void) {
260         char buf[SIZ];
261         long msgnum;
262         int count = 0;
263
264         artv_global_message_list = fopen(artv_tempfilename1, "r");
265         if (artv_global_message_list != NULL) {
266                 lprintf(CTDL_INFO, "Opened %s\n", artv_tempfilename1);
267                 while (fgets(buf, sizeof(buf),
268                       artv_global_message_list) != NULL) {
269                         msgnum = atol(buf);
270                         if (msgnum > 0L) {
271                                 artv_export_message(msgnum);
272                                 ++count;
273                         }
274                 }
275                 fclose(artv_global_message_list);
276         }
277         lprintf(CTDL_INFO, "Exported %d messages.\n", count);
278 }
279
280
281
282
283 void artv_do_export(void) {
284         struct config *buf;
285         buf = &config;
286         cprintf("%d Exporting all Citadel databases.\n", LISTING_FOLLOWS);
287
288         cprintf("version\n%d\n", REV_LEVEL);
289
290         /* export the config file (this is done using x-macros) */
291         cprintf("config\n");
292
293 #include "artv_serialize.h"
294 #include "dtds/config-defs.h"
295 #include "undef_data.h"
296
297         /* Export the control file */
298         get_control();
299         cprintf("control\n");
300         cprintf("%ld\n", CitControl.MMhighest);
301         cprintf("%u\n", CitControl.MMflags);
302         cprintf("%ld\n", CitControl.MMnextuser);
303         cprintf("%ld\n", CitControl.MMnextroom);
304         cprintf("%d\n", CitControl.version);
305
306         artv_export_users();
307         artv_export_rooms();
308         artv_export_floors();
309         artv_export_visits();
310         artv_export_messages();
311
312         cprintf("000\n");
313 }
314
315
316
317 void artv_import_config(void) {
318         char cbuf[SIZ];
319         struct config *buf;
320         buf = &config;
321
322         lprintf(CTDL_DEBUG, "Importing config file\n");
323
324 #include "artv_deserialize.h"
325 #include "dtds/config-defs.h"
326 #include "undef_data.h"
327
328         config.c_enable_fulltext = 0;   /* always disable */
329         put_config();
330         lprintf(CTDL_INFO, "Imported config file\n");
331 }
332
333
334 void artv_import_control(void) {
335         char buf[SIZ];
336
337         lprintf(CTDL_DEBUG, "Importing control file\n");
338         client_getln(buf, sizeof buf);  CitControl.MMhighest = atol(buf);
339         client_getln(buf, sizeof buf);  CitControl.MMflags = atoi(buf);
340         client_getln(buf, sizeof buf);  CitControl.MMnextuser = atol(buf);
341         client_getln(buf, sizeof buf);  CitControl.MMnextroom = atol(buf);
342         client_getln(buf, sizeof buf);  CitControl.version = atoi(buf);
343         CitControl.MMfulltext = (-1L);  /* always flush */
344         put_control();
345         lprintf(CTDL_INFO, "Imported control file\n");
346 }
347
348
349 void artv_import_user(void) {
350         char cbuf[SIZ];
351         struct ctdluser usbuf, *buf;
352         buf = &usbuf;
353 /*
354 #include "artv_deserialize.h"
355 #include "dtds/user-defs.h"
356 #include "undef_data.h"
357
358 /*/
359         client_getln(cbuf, sizeof cbuf);        buf->version = atoi(cbuf);
360         client_getln(cbuf, sizeof cbuf);        buf->uid = atoi(cbuf);
361         client_getln(buf->password, sizeof buf->password);
362         client_getln(cbuf, sizeof cbuf);        buf->flags = atoi(cbuf);
363         client_getln(cbuf, sizeof cbuf);        buf->timescalled = atol(cbuf);
364         client_getln(cbuf, sizeof cbuf);        buf->posted = atol(cbuf);
365         client_getln(cbuf, sizeof cbuf);        buf->axlevel = atoi(cbuf);
366         client_getln(cbuf, sizeof cbuf);        buf->usernum = atol(cbuf);
367         client_getln(cbuf, sizeof cbuf);        buf->lastcall = atol(cbuf);
368         client_getln(cbuf, sizeof cbuf);        buf->USuserpurge = atoi(cbuf);
369         client_getln(buf->fullname, sizeof buf->fullname);
370         client_getln(cbuf, sizeof cbuf);        buf->USscreenwidth = atoi(cbuf);
371         client_getln(cbuf, sizeof cbuf);        buf->USscreenheight = atoi(cbuf);
372 //*/
373         putuser(buf);
374 }
375
376
377 void artv_import_room(void) {
378         char cbuf[SIZ];
379         struct ctdlroom qrbuf, *buf;
380         long msgnum;
381         int msgcount = 0;
382
383         buf = &qrbuf;
384 /*
385 #include "artv_deserialize.h"
386 #include "dtds/room-defs.h"
387 #include "undef_data.h"
388
389 /*/
390         client_getln(buf->QRname, sizeof buf->QRname);
391         client_getln(buf->QRpasswd, sizeof buf->QRpasswd);
392         client_getln(cbuf, sizeof cbuf);        buf->QRroomaide = atol(cbuf);
393         client_getln(cbuf, sizeof cbuf);        buf->QRhighest = atol(cbuf);
394         client_getln(cbuf, sizeof cbuf);        buf->QRgen = atol(cbuf);
395         client_getln(cbuf, sizeof cbuf);        buf->QRflags = atoi(cbuf);
396         client_getln(buf->QRdirname, sizeof buf->QRdirname);
397         client_getln(cbuf, sizeof cbuf);        buf->QRinfo = atol(cbuf);
398         client_getln(cbuf, sizeof cbuf);        buf->QRfloor = atoi(cbuf);
399         client_getln(cbuf, sizeof cbuf);        buf->QRmtime = atol(cbuf);
400         client_getln(cbuf, sizeof cbuf);        buf->QRep.expire_mode = atoi(cbuf);
401         client_getln(cbuf, sizeof cbuf);        buf->QRep.expire_value = atoi(cbuf);
402         client_getln(cbuf, sizeof cbuf);        buf->QRnumber = atol(cbuf);
403         client_getln(cbuf, sizeof cbuf);        buf->QRorder = atoi(cbuf);
404         client_getln(cbuf, sizeof cbuf);        buf->QRflags2 = atoi(cbuf);
405         client_getln(cbuf, sizeof cbuf);        buf->QRdefaultview = atoi(cbuf);
406 //*/
407         putroom(buf);
408         lprintf(CTDL_INFO, "Imported room <%s>\n", qrbuf.QRname);
409         /* format of message list export is all message numbers output
410          * one per line terminated by a 0.
411          */
412         while (client_getln(cbuf, sizeof cbuf), msgnum = atol(cbuf), msgnum > 0) {
413                 CtdlSaveMsgPointerInRoom(qrbuf.QRname, msgnum, 0, NULL);
414                 ++msgcount;
415         }
416         lprintf(CTDL_INFO, "(%d messages)\n", msgcount);
417 }
418
419
420 void artv_import_floor(void) {
421         struct floor flbuf, *buf;
422         int i;
423         char cbuf[SIZ];
424
425         buf = & flbuf;
426         memset(buf, 0, sizeof(buf));
427         client_getln(cbuf, sizeof cbuf);        i = atoi(cbuf);
428 /*
429 #include "artv_deserialize.h"
430 #include "dtds/floor-defs.h"
431 #include "undef_data.h"
432 /*/
433         client_getln(cbuf, sizeof cbuf);        buf->f_flags = atoi(cbuf);
434         client_getln(buf->f_name, sizeof buf->f_name);
435         client_getln(cbuf, sizeof cbuf);        buf->f_ref_count = atoi(cbuf);
436         client_getln(cbuf, sizeof cbuf);        buf->f_ep.expire_mode = atoi(cbuf);
437         client_getln(cbuf, sizeof cbuf);        buf->f_ep.expire_value = atoi(cbuf);
438 //*/
439         putfloor(buf, i);
440         lprintf(CTDL_INFO, "Imported floor #%d (%s)\n", i, flbuf.f_name);
441 }
442
443
444 /* 
445  */
446 void artv_import_visit(void) {
447         struct visit vbuf;
448         char buf[SIZ];
449         int i;
450         int is_textual_seen = 0;
451
452         client_getln(buf, sizeof buf);  vbuf.v_roomnum = atol(buf);
453         client_getln(buf, sizeof buf);  vbuf.v_roomgen = atol(buf);
454         client_getln(buf, sizeof buf);  vbuf.v_usernum = atol(buf);
455
456         client_getln(buf, sizeof buf);
457         vbuf.v_lastseen = atol(buf);
458         for (i=0; buf[i]; ++i) if (!isdigit(buf[i])) is_textual_seen = 1;
459         if (is_textual_seen)    strcpy(vbuf.v_seen, buf);
460
461         client_getln(vbuf.v_answered, sizeof vbuf.v_answered);
462         client_getln(buf, sizeof buf);  vbuf.v_flags = atoi(buf);
463         client_getln(buf, sizeof buf);  vbuf.v_view = atoi(buf);
464         put_visit(&vbuf);
465         lprintf(CTDL_INFO, "Imported visit %ld/%ld/%ld\n",
466                 vbuf.v_roomnum, vbuf.v_roomgen, vbuf.v_usernum);
467 }
468
469
470
471 void artv_import_message(void) {
472         struct MetaData smi;
473         long msgnum;
474         long msglen;
475         FILE *fp;
476         char buf[SIZ];
477         char tempfile[PATH_MAX];
478         char *mbuf;
479
480         memset(&smi, 0, sizeof(struct MetaData));
481         client_getln(buf, sizeof buf);  msgnum = atol(buf);
482                                 smi.meta_msgnum = msgnum;
483         client_getln(buf, sizeof buf);  smi.meta_refcount = atoi(buf);
484         client_getln(smi.meta_content_type, sizeof smi.meta_content_type);
485
486         lprintf(CTDL_INFO, "message #%ld\n", msgnum);
487
488         /* decode base64 message text */
489         CtdlMakeTempFileName(tempfile, sizeof tempfile);
490         snprintf(buf, sizeof buf, "%s -d >%s", file_base64, tempfile);
491         fp = popen(buf, "w");
492         while (client_getln(buf, sizeof buf), strcasecmp(buf, END_OF_MESSAGE)) {
493                 fprintf(fp, "%s\n", buf);
494         }
495         pclose(fp);
496         fp = fopen(tempfile, "rb");
497         fseek(fp, 0L, SEEK_END);
498         msglen = ftell(fp);
499         fclose(fp);
500         lprintf(CTDL_DEBUG, "msglen = %ld\n", msglen);
501
502         mbuf = malloc(msglen);
503         fp = fopen(tempfile, "rb");
504         fread(mbuf, msglen, 1, fp);
505         fclose(fp);
506
507         cdb_store(CDB_MSGMAIN, &msgnum, sizeof(long), mbuf, msglen);
508
509         free(mbuf);
510         unlink(tempfile);
511
512         PutMetaData(&smi);
513         lprintf(CTDL_INFO, "Imported message %ld\n", msgnum);
514 }
515
516
517
518
519 void artv_do_import(void) {
520         char buf[SIZ];
521         char abuf[SIZ];
522         char s_version[SIZ];
523         int version;
524         long iterations;
525
526         unbuffer_output();
527
528         cprintf("%d sock it to me\n", SEND_LISTING);
529         abuf[0] = '\0';
530         unbuffer_output();
531         iterations = 0;
532         while (client_getln(buf, sizeof buf), strcmp(buf, "000")) {
533
534                 lprintf(CTDL_DEBUG, "import keyword: <%s>\n", buf);
535                 if ((abuf[0] == '\0') || (strcasecmp(buf, abuf))) {
536                         cprintf ("\n\nImporting datatype %s\n", buf);
537                         strncpy (abuf, buf, SIZ);       
538                         iterations = 0;
539                 }
540                 else {
541                         cprintf(".");
542                         if (iterations % 64 == 0)
543                                 cprintf("\n");
544                         
545                 }
546                 
547                 if (!strcasecmp(buf, "version")) {
548                         client_getln(s_version, sizeof s_version);
549                         version = atoi(s_version);
550                         if ((version<EXPORT_REV_MIN) || (version>REV_LEVEL)) {
551                                 lprintf(CTDL_ERR, "Version mismatch in ARTV import; aborting\n");
552                                 break;
553                         }
554                 }
555                 else if (!strcasecmp(buf, "config")) artv_import_config();
556                 else if (!strcasecmp(buf, "control")) artv_import_control();
557                 else if (!strcasecmp(buf, "user")) artv_import_user();
558                 else if (!strcasecmp(buf, "room")) artv_import_room();
559                 else if (!strcasecmp(buf, "floor")) artv_import_floor();
560                 else if (!strcasecmp(buf, "visit")) artv_import_visit();
561                 else if (!strcasecmp(buf, "message")) artv_import_message();
562                 else break;
563                 iterations ++;
564         }
565         lprintf(CTDL_INFO, "Invalid keyword <%s>.  Flushing input.\n", buf);
566         while (client_getln(buf, sizeof buf), strcmp(buf, "000"))  ;;
567         rebuild_euid_index();
568 }
569
570
571
572 void cmd_artv(char *cmdbuf) {
573         char cmd[32];
574         static int is_running = 0;
575
576         if (CtdlAccessCheck(ac_internal)) return;
577         if (is_running) {
578                 cprintf("%d The importer/exporter is already running.\n",
579                         ERROR + RESOURCE_BUSY);
580                 return;
581         }
582         is_running = 1;
583
584         CtdlMakeTempFileName(artv_tempfilename1, sizeof artv_tempfilename1);
585         CtdlMakeTempFileName(artv_tempfilename2, sizeof artv_tempfilename2);
586
587         extract_token(cmd, cmdbuf, 0, '|', sizeof cmd);
588         if (!strcasecmp(cmd, "export")) artv_do_export();
589         else if (!strcasecmp(cmd, "import")) artv_do_import();
590         else cprintf("%d illegal command\n", ERROR + ILLEGAL_VALUE);
591
592         unlink(artv_tempfilename1);
593         unlink(artv_tempfilename2);
594
595         is_running = 0;
596 }
597
598
599
600
601 CTDL_MODULE_INIT(vandelay)
602 {
603         CtdlRegisterProtoHook(cmd_artv, "ARTV", "import/export data store");
604
605         /* return our Subversion id for the Log */
606         return "$Id$";
607 }