* if the client disconnects, abort the ARTV EXPORT
[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         t_context *Ctx;
264
265         Ctx = CC;
266         artv_global_message_list = fopen(artv_tempfilename1, "r");
267         if (artv_global_message_list != NULL) {
268                 lprintf(CTDL_INFO, "Opened %s\n", artv_tempfilename1);
269                 while ((Ctx->kill_me != 1) && 
270                        (fgets(buf, sizeof(buf), artv_global_message_list) != NULL)) {
271                         msgnum = atol(buf);
272                         if (msgnum > 0L) {
273                                 artv_export_message(msgnum);
274                                 ++count;
275                         }
276                 }
277                 fclose(artv_global_message_list);
278         }
279         if (Ctx->kill_me != 1)
280                 lprintf(CTDL_INFO, "Exported %d messages.\n", count);
281         else
282                 lprintf(CTDL_ERR, "Export aborted due to client disconnect! \n");
283 }
284
285
286
287
288 void artv_do_export(void) {
289         struct config *buf;
290         buf = &config;
291         t_context *Ctx;
292
293         Ctx = CC;
294         cprintf("%d Exporting all Citadel databases.\n", LISTING_FOLLOWS);
295
296         cprintf("version\n%d\n", REV_LEVEL);
297
298         /* export the config file (this is done using x-macros) */
299         cprintf("config\n");
300
301 #include "artv_serialize.h"
302 #include "dtds/config-defs.h"
303 #include "undef_data.h"
304
305         /* Export the control file */
306         get_control();
307         cprintf("control\n");
308         cprintf("%ld\n", CitControl.MMhighest);
309         cprintf("%u\n", CitControl.MMflags);
310         cprintf("%ld\n", CitControl.MMnextuser);
311         cprintf("%ld\n", CitControl.MMnextroom);
312         cprintf("%d\n", CitControl.version);
313         if (Ctx->kill_me != 1)
314                 artv_export_users();
315         if (Ctx->kill_me != 1)
316                 artv_export_rooms();
317         if (Ctx->kill_me != 1)
318                 artv_export_floors();
319         if (Ctx->kill_me != 1)
320                 artv_export_visits();
321         if (Ctx->kill_me != 1)
322                 artv_export_messages();
323
324         cprintf("000\n");
325 }
326
327
328
329 void artv_import_config(void) {
330         char cbuf[SIZ];
331         struct config *buf;
332         buf = &config;
333
334         lprintf(CTDL_DEBUG, "Importing config file\n");
335
336 #include "artv_deserialize.h"
337 #include "dtds/config-defs.h"
338 #include "undef_data.h"
339
340         config.c_enable_fulltext = 0;   /* always disable */
341         put_config();
342         lprintf(CTDL_INFO, "Imported config file\n");
343 }
344
345
346 void artv_import_control(void) {
347         char buf[SIZ];
348
349         lprintf(CTDL_DEBUG, "Importing control file\n");
350         client_getln(buf, sizeof buf);  CitControl.MMhighest = atol(buf);
351         client_getln(buf, sizeof buf);  CitControl.MMflags = atoi(buf);
352         client_getln(buf, sizeof buf);  CitControl.MMnextuser = atol(buf);
353         client_getln(buf, sizeof buf);  CitControl.MMnextroom = atol(buf);
354         client_getln(buf, sizeof buf);  CitControl.version = atoi(buf);
355         CitControl.MMfulltext = (-1L);  /* always flush */
356         put_control();
357         lprintf(CTDL_INFO, "Imported control file\n");
358 }
359
360
361 void artv_import_user(void) {
362         char cbuf[SIZ];
363         struct ctdluser usbuf, *buf;
364         buf = &usbuf;
365 /*
366 #include "artv_deserialize.h"
367 #include "dtds/user-defs.h"
368 #include "undef_data.h"
369
370 /*/
371         client_getln(cbuf, sizeof cbuf);        buf->version = atoi(cbuf);
372         client_getln(cbuf, sizeof cbuf);        buf->uid = atoi(cbuf);
373         client_getln(buf->password, sizeof buf->password);
374         client_getln(cbuf, sizeof cbuf);        buf->flags = atoi(cbuf);
375         client_getln(cbuf, sizeof cbuf);        buf->timescalled = atol(cbuf);
376         client_getln(cbuf, sizeof cbuf);        buf->posted = atol(cbuf);
377         client_getln(cbuf, sizeof cbuf);        buf->axlevel = atoi(cbuf);
378         client_getln(cbuf, sizeof cbuf);        buf->usernum = atol(cbuf);
379         client_getln(cbuf, sizeof cbuf);        buf->lastcall = atol(cbuf);
380         client_getln(cbuf, sizeof cbuf);        buf->USuserpurge = atoi(cbuf);
381         client_getln(buf->fullname, sizeof buf->fullname);
382         client_getln(cbuf, sizeof cbuf);        buf->USscreenwidth = atoi(cbuf);
383         client_getln(cbuf, sizeof cbuf);        buf->USscreenheight = atoi(cbuf);
384 //*/
385         putuser(buf);
386 }
387
388
389 void artv_import_room(void) {
390         char cbuf[SIZ];
391         struct ctdlroom qrbuf, *buf;
392         long msgnum;
393         int msgcount = 0;
394
395         buf = &qrbuf;
396 /*
397 #include "artv_deserialize.h"
398 #include "dtds/room-defs.h"
399 #include "undef_data.h"
400
401 /*/
402         client_getln(buf->QRname, sizeof buf->QRname);
403         client_getln(buf->QRpasswd, sizeof buf->QRpasswd);
404         client_getln(cbuf, sizeof cbuf);        buf->QRroomaide = atol(cbuf);
405         client_getln(cbuf, sizeof cbuf);        buf->QRhighest = atol(cbuf);
406         client_getln(cbuf, sizeof cbuf);        buf->QRgen = atol(cbuf);
407         client_getln(cbuf, sizeof cbuf);        buf->QRflags = atoi(cbuf);
408         client_getln(buf->QRdirname, sizeof buf->QRdirname);
409         client_getln(cbuf, sizeof cbuf);        buf->QRinfo = atol(cbuf);
410         client_getln(cbuf, sizeof cbuf);        buf->QRfloor = atoi(cbuf);
411         client_getln(cbuf, sizeof cbuf);        buf->QRmtime = atol(cbuf);
412         client_getln(cbuf, sizeof cbuf);        buf->QRep.expire_mode = atoi(cbuf);
413         client_getln(cbuf, sizeof cbuf);        buf->QRep.expire_value = atoi(cbuf);
414         client_getln(cbuf, sizeof cbuf);        buf->QRnumber = atol(cbuf);
415         client_getln(cbuf, sizeof cbuf);        buf->QRorder = atoi(cbuf);
416         client_getln(cbuf, sizeof cbuf);        buf->QRflags2 = atoi(cbuf);
417         client_getln(cbuf, sizeof cbuf);        buf->QRdefaultview = atoi(cbuf);
418 //*/
419         putroom(buf);
420         lprintf(CTDL_INFO, "Imported room <%s>\n", qrbuf.QRname);
421         /* format of message list export is all message numbers output
422          * one per line terminated by a 0.
423          */
424         while (client_getln(cbuf, sizeof cbuf), msgnum = atol(cbuf), msgnum > 0) {
425                 CtdlSaveMsgPointerInRoom(qrbuf.QRname, msgnum, 0, NULL);
426                 ++msgcount;
427         }
428         lprintf(CTDL_INFO, "(%d messages)\n", msgcount);
429 }
430
431
432 void artv_import_floor(void) {
433         struct floor flbuf, *buf;
434         int i;
435         char cbuf[SIZ];
436
437         buf = & flbuf;
438         memset(buf, 0, sizeof(buf));
439         client_getln(cbuf, sizeof cbuf);        i = atoi(cbuf);
440 /*
441 #include "artv_deserialize.h"
442 #include "dtds/floor-defs.h"
443 #include "undef_data.h"
444 /*/
445         client_getln(cbuf, sizeof cbuf);        buf->f_flags = atoi(cbuf);
446         client_getln(buf->f_name, sizeof buf->f_name);
447         client_getln(cbuf, sizeof cbuf);        buf->f_ref_count = atoi(cbuf);
448         client_getln(cbuf, sizeof cbuf);        buf->f_ep.expire_mode = atoi(cbuf);
449         client_getln(cbuf, sizeof cbuf);        buf->f_ep.expire_value = atoi(cbuf);
450 //*/
451         putfloor(buf, i);
452         lprintf(CTDL_INFO, "Imported floor #%d (%s)\n", i, flbuf.f_name);
453 }
454
455
456 /* 
457  */
458 void artv_import_visit(void) {
459         struct visit vbuf;
460         char buf[SIZ];
461         int i;
462         int is_textual_seen = 0;
463
464         client_getln(buf, sizeof buf);  vbuf.v_roomnum = atol(buf);
465         client_getln(buf, sizeof buf);  vbuf.v_roomgen = atol(buf);
466         client_getln(buf, sizeof buf);  vbuf.v_usernum = atol(buf);
467
468         client_getln(buf, sizeof buf);
469         vbuf.v_lastseen = atol(buf);
470         for (i=0; buf[i]; ++i) if (!isdigit(buf[i])) is_textual_seen = 1;
471         if (is_textual_seen)    strcpy(vbuf.v_seen, buf);
472
473         client_getln(vbuf.v_answered, sizeof vbuf.v_answered);
474         client_getln(buf, sizeof buf);  vbuf.v_flags = atoi(buf);
475         client_getln(buf, sizeof buf);  vbuf.v_view = atoi(buf);
476         put_visit(&vbuf);
477         lprintf(CTDL_INFO, "Imported visit %ld/%ld/%ld\n",
478                 vbuf.v_roomnum, vbuf.v_roomgen, vbuf.v_usernum);
479 }
480
481
482
483 void artv_import_message(void) {
484         struct MetaData smi;
485         long msgnum;
486         long msglen;
487         FILE *fp;
488         char buf[SIZ];
489         char tempfile[PATH_MAX];
490         char *mbuf;
491
492         memset(&smi, 0, sizeof(struct MetaData));
493         client_getln(buf, sizeof buf);  msgnum = atol(buf);
494                                 smi.meta_msgnum = msgnum;
495         client_getln(buf, sizeof buf);  smi.meta_refcount = atoi(buf);
496         client_getln(smi.meta_content_type, sizeof smi.meta_content_type);
497
498         lprintf(CTDL_INFO, "message #%ld\n", msgnum);
499
500         /* decode base64 message text */
501         CtdlMakeTempFileName(tempfile, sizeof tempfile);
502         snprintf(buf, sizeof buf, "%s -d >%s", file_base64, tempfile);
503         fp = popen(buf, "w");
504         while (client_getln(buf, sizeof buf), strcasecmp(buf, END_OF_MESSAGE)) {
505                 fprintf(fp, "%s\n", buf);
506         }
507         pclose(fp);
508         fp = fopen(tempfile, "rb");
509         fseek(fp, 0L, SEEK_END);
510         msglen = ftell(fp);
511         fclose(fp);
512         lprintf(CTDL_DEBUG, "msglen = %ld\n", msglen);
513
514         mbuf = malloc(msglen);
515         fp = fopen(tempfile, "rb");
516         fread(mbuf, msglen, 1, fp);
517         fclose(fp);
518
519         cdb_store(CDB_MSGMAIN, &msgnum, sizeof(long), mbuf, msglen);
520
521         free(mbuf);
522         unlink(tempfile);
523
524         PutMetaData(&smi);
525         lprintf(CTDL_INFO, "Imported message %ld\n", msgnum);
526 }
527
528
529
530
531 void artv_do_import(void) {
532         char buf[SIZ];
533         char abuf[SIZ];
534         char s_version[SIZ];
535         int version;
536         long iterations;
537
538         unbuffer_output();
539
540         cprintf("%d sock it to me\n", SEND_LISTING);
541         abuf[0] = '\0';
542         unbuffer_output();
543         iterations = 0;
544         while (client_getln(buf, sizeof buf), strcmp(buf, "000")) {
545
546                 lprintf(CTDL_DEBUG, "import keyword: <%s>\n", buf);
547                 if ((abuf[0] == '\0') || (strcasecmp(buf, abuf))) {
548                         cprintf ("\n\nImporting datatype %s\n", buf);
549                         strncpy (abuf, buf, SIZ);       
550                         iterations = 0;
551                 }
552                 else {
553                         cprintf(".");
554                         if (iterations % 64 == 0)
555                                 cprintf("\n");
556                         
557                 }
558                 
559                 if (!strcasecmp(buf, "version")) {
560                         client_getln(s_version, sizeof s_version);
561                         version = atoi(s_version);
562                         if ((version<EXPORT_REV_MIN) || (version>REV_LEVEL)) {
563                                 lprintf(CTDL_ERR, "Version mismatch in ARTV import; aborting\n");
564                                 break;
565                         }
566                 }
567                 else if (!strcasecmp(buf, "config")) artv_import_config();
568                 else if (!strcasecmp(buf, "control")) artv_import_control();
569                 else if (!strcasecmp(buf, "user")) artv_import_user();
570                 else if (!strcasecmp(buf, "room")) artv_import_room();
571                 else if (!strcasecmp(buf, "floor")) artv_import_floor();
572                 else if (!strcasecmp(buf, "visit")) artv_import_visit();
573                 else if (!strcasecmp(buf, "message")) artv_import_message();
574                 else break;
575                 iterations ++;
576         }
577         lprintf(CTDL_INFO, "Invalid keyword <%s>.  Flushing input.\n", buf);
578         while (client_getln(buf, sizeof buf), strcmp(buf, "000"))  ;;
579         rebuild_euid_index();
580 }
581
582
583
584 void cmd_artv(char *cmdbuf) {
585         char cmd[32];
586         static int is_running = 0;
587
588         if (CtdlAccessCheck(ac_internal)) return;
589         if (is_running) {
590                 cprintf("%d The importer/exporter is already running.\n",
591                         ERROR + RESOURCE_BUSY);
592                 return;
593         }
594         is_running = 1;
595
596         CtdlMakeTempFileName(artv_tempfilename1, sizeof artv_tempfilename1);
597         CtdlMakeTempFileName(artv_tempfilename2, sizeof artv_tempfilename2);
598
599         extract_token(cmd, cmdbuf, 0, '|', sizeof cmd);
600         if (!strcasecmp(cmd, "export")) artv_do_export();
601         else if (!strcasecmp(cmd, "import")) artv_do_import();
602         else cprintf("%d illegal command\n", ERROR + ILLEGAL_VALUE);
603
604         unlink(artv_tempfilename1);
605         unlink(artv_tempfilename2);
606
607         is_running = 0;
608 }
609
610
611
612
613 CTDL_MODULE_INIT(vandelay)
614 {
615         CtdlRegisterProtoHook(cmd_artv, "ARTV", "import/export data store");
616
617         /* return our Subversion id for the Log */
618         return "$Id$";
619 }