66022d9204246aa0efa702cb4d67123d815afa37
[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 <libcitadel.h>
34 #include "citadel.h"
35 #include "server.h"
36 #include "citserver.h"
37 #include "support.h"
38 #include "config.h"
39 #include "database.h"
40 #include "msgbase.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         client_write("user\n", 5);
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 void artv_dump_users_backend(struct ctdluser *buf, void *data) {
81         client_write("user\n", 5);
82
83 #include "artv_dump.h"
84 #include "dtds/user-defs.h"
85 #include "undef_data.h"
86         cprintf("\n");
87 }
88
89
90 INLINE int cprintdot (long *iterations)
91 {
92         int retval = 0;
93         
94         retval += client_write(".", 1);
95         ++(*iterations);
96         if ((*iterations) % 64 == 0)
97                 retval += client_write("\n", 1);
98         return retval;
99 }
100
101
102
103 void artv_export_users(void) {
104         ForEachUser(artv_export_users_backend, NULL);
105 }
106
107 void artv_dump_users(void) {
108         ForEachUser(artv_dump_users_backend, NULL);
109 }
110
111
112 void artv_export_room_msg(long msgnum, void *userdata) {
113         cprintf("%ld\n", msgnum);
114         fprintf(artv_global_message_list, "%ld\n", msgnum);
115 }
116
117 void artv_dump_room_msg(long msgnum, void *userdata) {
118         cprintf(" msgnum: %ld\n", msgnum);
119         fprintf(artv_global_message_list, "%ld\n", msgnum);
120         cprintf("\n");
121 }//// TODO
122
123
124 void artv_export_rooms_backend(struct ctdlroom *buf, void *data) {
125         client_write("room\n", 5);
126 /*
127 #include "artv_serialize.h"
128 #include "dtds/room-defs.h"
129 #include "undef_data.h"
130 */
131         cprintf("%s\n", buf->QRname);
132         cprintf("%s\n", buf->QRpasswd);
133         cprintf("%ld\n", buf->QRroomaide);
134         cprintf("%ld\n", buf->QRhighest);
135         cprintf("%ld\n", (long)buf->QRgen);
136         cprintf("%u\n", buf->QRflags);
137         cprintf("%s\n", buf->QRdirname);
138         cprintf("%ld\n", buf->QRinfo);
139         cprintf("%d\n", buf->QRfloor);
140         cprintf("%ld\n", (long)buf->QRmtime);
141         cprintf("%d\n", buf->QRep.expire_mode);
142         cprintf("%d\n", buf->QRep.expire_value);
143         cprintf("%ld\n", buf->QRnumber);
144         cprintf("%d\n", buf->QRorder);
145         cprintf("%u\n", buf->QRflags2);
146         cprintf("%d\n", buf->QRdefaultview);
147
148         getroom(&CC->room, buf->QRname);
149         /* format of message list export is all message numbers output
150          * one per line terminated by a 0.
151          */
152 //*/
153         getroom(&CC->room, buf->QRname);
154         /* format of message list export is all message numbers output
155          * one per line terminated by a 0.
156          */
157         CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL,
158                 artv_export_room_msg, NULL);
159         cprintf("0\n");
160
161 }
162
163 void artv_dump_rooms_backend(struct ctdlroom *buf, void *data) {
164         client_write("room\n", 5);
165
166 #include "artv_dump.h"
167 #include "dtds/room-defs.h"
168 #include "undef_data.h"
169
170         getroom(&CC->room, buf->QRname);
171         /* format of message list export is all message numbers output
172          * one per line terminated by a 0.
173          */
174 //*/
175         getroom(&CC->room, buf->QRname);
176         /* format of message list export is all message numbers output
177          * one per line terminated by a 0.
178          */
179         CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL,
180                 artv_dump_room_msg, NULL);
181         cprintf("\n\n");
182
183 }
184
185
186
187 void artv_export_rooms(void) {
188         char cmd[SIZ];
189         artv_global_message_list = fopen(artv_tempfilename1, "w");
190         if (artv_global_message_list != NULL) {
191                 ForEachRoom(artv_export_rooms_backend, NULL);
192                 fclose(artv_global_message_list);
193         }
194
195         /*
196          * Process the 'global' message list.  (Sort it and remove dups.
197          * Dups are ok because a message may be in more than one room, but
198          * this will be handled by exporting the reference count, not by
199          * exporting the message multiple times.)
200          */
201         snprintf(cmd, sizeof cmd, "sort <%s >%s", artv_tempfilename1, artv_tempfilename2);
202         system(cmd);
203         snprintf(cmd, sizeof cmd, "uniq <%s >%s", artv_tempfilename2, artv_tempfilename1);
204         system(cmd);
205 }
206
207 void artv_dump_rooms(void) {
208         char cmd[SIZ];
209         artv_global_message_list = fopen(artv_tempfilename1, "w");
210         if (artv_global_message_list != NULL) {
211                 ForEachRoom(artv_dump_rooms_backend, NULL);
212                 fclose(artv_global_message_list);
213         }
214
215         /*
216          * Process the 'global' message list.  (Sort it and remove dups.
217          * Dups are ok because a message may be in more than one room, but
218          * this will be handled by exporting the reference count, not by
219          * exporting the message multiple times.)
220          */
221         snprintf(cmd, sizeof cmd, "sort <%s >%s", artv_tempfilename1, artv_tempfilename2);
222         system(cmd);
223         snprintf(cmd, sizeof cmd, "uniq <%s >%s", artv_tempfilename2, artv_tempfilename1);
224         system(cmd);
225 }
226
227
228 void artv_export_floors(void) {
229         struct floor qfbuf, *buf;
230         int i;
231
232         for (i=0; i < MAXFLOORS; ++i) {
233                 client_write("floor\n", 6);
234                 cprintf("%d\n", i);
235                 getfloor(&qfbuf, i);
236                 buf = &qfbuf;
237 /*
238 #include "artv_serialize.h"
239 #include "dtds/floor-defs.h"
240 #include "undef_data.h"
241 /*/
242                 cprintf("%u\n", buf->f_flags);
243                 cprintf("%s\n", buf->f_name);
244                 cprintf("%d\n", buf->f_ref_count);
245                 cprintf("%d\n", buf->f_ep.expire_mode);
246                 cprintf("%d\n", buf->f_ep.expire_value);
247 //*/
248         }
249 }
250
251 void artv_dump_floors(void) {
252         struct floor qfbuf, *buf;
253         int i;
254
255         for (i=0; i < MAXFLOORS; ++i) {
256                 client_write("floor\n", 6);
257                 cprintf("%d\n", i);
258                 getfloor(&qfbuf, i);
259                 buf = &qfbuf;
260
261 #include "artv_serialize.h"
262 #include "dtds/floor-defs.h"
263 #include "undef_data.h"
264         }
265 }
266
267
268
269
270
271 /* 
272  *  Traverse the visits file...
273  */
274 void artv_export_visits(void) {
275         struct visit vbuf;
276         struct cdbdata *cdbv;
277
278         cdb_rewind(CDB_VISIT);
279
280         while (cdbv = cdb_next_item(CDB_VISIT), cdbv != NULL) {
281                 memset(&vbuf, 0, sizeof(struct visit));
282                 memcpy(&vbuf, cdbv->ptr,
283                        ((cdbv->len > sizeof(struct visit)) ?
284                         sizeof(struct visit) : cdbv->len));
285                 cdb_free(cdbv);
286
287                 client_write("visit\n", 6);
288                 cprintf("%ld\n", vbuf.v_roomnum);
289                 cprintf("%ld\n", vbuf.v_roomgen);
290                 cprintf("%ld\n", vbuf.v_usernum);
291
292                 if (!IsEmptyStr(vbuf.v_seen)) {
293                         cprintf("%s\n", vbuf.v_seen);
294                 }
295                 else {
296                         cprintf("%ld\n", vbuf.v_lastseen);
297                 }
298
299                 cprintf("%s\n", vbuf.v_answered);
300                 cprintf("%u\n", vbuf.v_flags);
301                 cprintf("%d\n", vbuf.v_view);
302         }
303 }
304
305 /* 
306  *  Traverse the visits file...
307  */
308 void artv_dump_visits(void) {
309         struct visit vbuf;
310         struct cdbdata *cdbv;
311
312         cdb_rewind(CDB_VISIT);
313
314         while (cdbv = cdb_next_item(CDB_VISIT), cdbv != NULL) {
315                 memset(&vbuf, 0, sizeof(struct visit));
316                 memcpy(&vbuf, cdbv->ptr,
317                        ((cdbv->len > sizeof(struct visit)) ?
318                         sizeof(struct visit) : cdbv->len));
319                 cdb_free(cdbv);
320
321                 client_write("---visit---\n", 12);
322                 cprintf(" Room-Num: %ld\n", vbuf.v_roomnum);
323                 cprintf(" Room-Gen%ld\n", vbuf.v_roomgen);
324                 cprintf(" User-Num%ld\n", vbuf.v_usernum);
325
326                 if (!IsEmptyStr(vbuf.v_seen)) {
327                         cprintf(" Seen: %s\n", vbuf.v_seen);
328                 }
329                 else {
330                         cprintf(" LastSeen: %ld\n", vbuf.v_lastseen);
331                 }
332
333                 cprintf(" Answered: %s\n", vbuf.v_answered);
334                 cprintf(" Flags: %u\n", vbuf.v_flags);
335                 cprintf(" View: %d\n", vbuf.v_view);
336         }
337 }
338
339
340 void artv_export_message(long msgnum) {
341         struct MetaData smi;
342         struct CtdlMessage *msg;
343         struct ser_ret smr;
344         FILE *fp;
345         char buf[SIZ];
346         char tempfile[PATH_MAX];
347
348         msg = CtdlFetchMessage(msgnum, 1);
349         if (msg == NULL) return;        /* fail silently */
350
351         client_write("message\n", 8);
352         GetMetaData(&smi, msgnum);
353         cprintf("%ld\n", msgnum);
354         cprintf("%d\n", smi.meta_refcount);
355         cprintf("%s\n", smi.meta_content_type);
356
357         serialize_message(&smr, msg);
358         CtdlFreeMessage(msg);
359
360         /* write it in base64 */
361         CtdlMakeTempFileName(tempfile, sizeof tempfile);
362         snprintf(buf, sizeof buf, "%s -e >%s", file_base64, tempfile);
363         fp = popen(buf, "w");
364         fwrite(smr.ser, smr.len, 1, fp);
365         pclose(fp);
366
367         free(smr.ser);
368
369         fp = fopen(tempfile, "r");
370         unlink(tempfile);
371         if (fp != NULL) {
372                 while (fgets(buf, sizeof(buf), fp) != NULL) {
373                         buf[strlen(buf)-1] = 0;
374                         cprintf("%s\n", buf);
375                 }
376                 fclose(fp);
377         }
378         cprintf("%s\n", END_OF_MESSAGE);
379 }
380
381 void artv_dump_message(long msgnum) {
382         struct MetaData smi;
383         struct CtdlMessage *msg;
384
385         msg = CtdlFetchMessage(msgnum, 1);
386         if (msg == NULL) return;        /* fail silently */
387
388         client_write("message\n", 8);
389         GetMetaData(&smi, msgnum);
390         cprintf(" MessageNum: %ld\n", msgnum);
391         cprintf(" MetaRefcount: %d\n", smi.meta_refcount);
392         cprintf(" MetaContentType: %s\n", smi.meta_content_type);
393
394         dump_message(msg, 80);
395         CtdlFreeMessage(msg);
396
397         cprintf("%s\n", END_OF_MESSAGE);
398 }
399
400
401
402 void artv_export_messages(void) {
403         char buf[SIZ];
404         long msgnum;
405         int count = 0;
406         t_context *Ctx;
407
408         Ctx = CC;
409         artv_global_message_list = fopen(artv_tempfilename1, "r");
410         if (artv_global_message_list != NULL) {
411                 CtdlLogPrintf(CTDL_INFO, "Opened %s\n", artv_tempfilename1);
412                 while ((Ctx->kill_me != 1) && 
413                        (fgets(buf, sizeof(buf), artv_global_message_list) != NULL)) {
414                         msgnum = atol(buf);
415                         if (msgnum > 0L) {
416                                 artv_export_message(msgnum);
417                                 ++count;
418                         }
419                 }
420                 fclose(artv_global_message_list);
421         }
422         if (Ctx->kill_me != 1)
423                 CtdlLogPrintf(CTDL_INFO, "Exported %d messages.\n", count);
424         else
425                 CtdlLogPrintf(CTDL_ERR, "Export aborted due to client disconnect! \n");
426 }
427
428 void artv_dump_messages(void) {
429         char buf[SIZ];
430         long msgnum;
431         int count = 0;
432         t_context *Ctx;
433
434         Ctx = CC;
435         artv_global_message_list = fopen(artv_tempfilename1, "r");
436         if (artv_global_message_list != NULL) {
437                 CtdlLogPrintf(CTDL_INFO, "Opened %s\n", artv_tempfilename1);
438                 while ((Ctx->kill_me != 1) && 
439                        (fgets(buf, sizeof(buf), artv_global_message_list) != NULL)) {
440                         msgnum = atol(buf);
441                         if (msgnum > 0L) {
442                                 artv_dump_message(msgnum);
443                                 ++count;
444                         }
445                 }
446                 fclose(artv_global_message_list);
447         }
448         if (Ctx->kill_me != 1)
449                 CtdlLogPrintf(CTDL_INFO, "Exported %d messages.\n", count);
450         else
451                 CtdlLogPrintf(CTDL_ERR, "Export aborted due to client disconnect! \n");
452 }
453
454
455
456
457 void artv_do_export(void) {
458         struct config *buf;
459         buf = &config;
460         t_context *Ctx;
461
462         Ctx = CC;
463         cprintf("%d Exporting all Citadel databases.\n", LISTING_FOLLOWS);
464
465         cprintf("version\n%d\n", REV_LEVEL);
466
467         /* export the config file (this is done using x-macros) */
468         client_write("config\n", 7);
469
470 #include "artv_serialize.h"
471 #include "dtds/config-defs.h"
472 #include "undef_data.h"
473         client_write("\n", 1);
474         
475         /* Export the control file */
476         get_control();
477         client_write("control\n", 8);
478         cprintf("%ld\n", CitControl.MMhighest);
479         cprintf("%u\n", CitControl.MMflags);
480         cprintf("%ld\n", CitControl.MMnextuser);
481         cprintf("%ld\n", CitControl.MMnextroom);
482         cprintf("%d\n", CitControl.version);
483         if (Ctx->kill_me != 1)
484                 artv_export_users();
485         if (Ctx->kill_me != 1)
486                 artv_export_rooms();
487         if (Ctx->kill_me != 1)
488                 artv_export_floors();
489         if (Ctx->kill_me != 1)
490                 artv_export_visits();
491         if (Ctx->kill_me != 1)
492                 artv_export_messages();
493
494         client_write("000\n", 4);
495 }
496
497 void artv_do_dump(void) {
498         struct config *buf;
499         buf = &config;
500         t_context *Ctx;
501
502         Ctx = CC;
503         cprintf("%d dumping Citadel structures.\n", LISTING_FOLLOWS);
504
505         cprintf("version\n%d\n", REV_LEVEL);
506
507         /* export the config file (this is done using x-macros) */
508         client_write("config\n", 7);
509
510 #include "artv_dump.h"
511 #include "dtds/config-defs.h"
512 #include "undef_data.h"
513
514         /* Export the control file */
515         get_control();
516         client_write("control\n", 8);
517         cprintf(" MMhighest: %ld\n", CitControl.MMhighest);
518         cprintf(" MMflags: %u\n", CitControl.MMflags);
519         cprintf(" MMnextuser: %ld\n", CitControl.MMnextuser);
520         cprintf(" MMnextroom: %ld\n", CitControl.MMnextroom);
521         cprintf(" version: %d\n\n", CitControl.version);
522         if (Ctx->kill_me != 1)
523                 artv_dump_users();
524         if (Ctx->kill_me != 1)
525                 artv_dump_rooms();
526         if (Ctx->kill_me != 1)
527                 artv_dump_floors();
528         if (Ctx->kill_me != 1)
529                 artv_dump_visits();
530         if (Ctx->kill_me != 1)
531                 artv_dump_messages();
532
533         client_write("000\n", 4);
534 }
535
536
537
538 void artv_import_config(void) {
539         char cbuf[SIZ];
540         struct config *buf;
541         buf = &config;
542
543         CtdlLogPrintf(CTDL_DEBUG, "Importing config file\n");
544
545 #include "artv_deserialize.h"
546 #include "dtds/config-defs.h"
547 #include "undef_data.h"
548
549         config.c_enable_fulltext = 0;   /* always disable */
550         put_config();
551         CtdlLogPrintf(CTDL_INFO, "Imported config file\n");
552 }
553
554
555 void artv_import_control(void) {
556         char buf[SIZ];
557
558         CtdlLogPrintf(CTDL_DEBUG, "Importing control file\n");
559         client_getln(buf, sizeof buf);  CitControl.MMhighest = atol(buf);
560         client_getln(buf, sizeof buf);  CitControl.MMflags = atoi(buf);
561         client_getln(buf, sizeof buf);  CitControl.MMnextuser = atol(buf);
562         client_getln(buf, sizeof buf);  CitControl.MMnextroom = atol(buf);
563         client_getln(buf, sizeof buf);  CitControl.version = atoi(buf);
564         CitControl.MMfulltext = (-1L);  /* always flush */
565         put_control();
566         CtdlLogPrintf(CTDL_INFO, "Imported control file\n");
567 }
568
569
570 void artv_import_user(void) {
571         char cbuf[SIZ];
572         struct ctdluser usbuf, *buf;
573         buf = &usbuf;
574 /*
575 #include "artv_deserialize.h"
576 #include "dtds/user-defs.h"
577 #include "undef_data.h"
578
579 /*/
580         client_getln(cbuf, sizeof cbuf);        buf->version = atoi(cbuf);
581         client_getln(cbuf, sizeof cbuf);        buf->uid = atoi(cbuf);
582         client_getln(buf->password, sizeof buf->password);
583         client_getln(cbuf, sizeof cbuf);        buf->flags = atoi(cbuf);
584         client_getln(cbuf, sizeof cbuf);        buf->timescalled = atol(cbuf);
585         client_getln(cbuf, sizeof cbuf);        buf->posted = atol(cbuf);
586         client_getln(cbuf, sizeof cbuf);        buf->axlevel = atoi(cbuf);
587         client_getln(cbuf, sizeof cbuf);        buf->usernum = atol(cbuf);
588         client_getln(cbuf, sizeof cbuf);        buf->lastcall = atol(cbuf);
589         client_getln(cbuf, sizeof cbuf);        buf->USuserpurge = atoi(cbuf);
590         client_getln(buf->fullname, sizeof buf->fullname);
591         client_getln(cbuf, sizeof cbuf);        buf->USscreenwidth = atoi(cbuf);
592         client_getln(cbuf, sizeof cbuf);        buf->USscreenheight = atoi(cbuf);
593 //*/
594         putuser(buf);
595 }
596
597
598 void artv_import_room(long *iterations) {
599         char cbuf[SIZ];
600         struct ctdlroom qrbuf, *buf;
601         long msgnum;
602         int msgcount = 0;
603
604         buf = &qrbuf;
605 /*
606 #include "artv_deserialize.h"
607 #include "dtds/room-defs.h"
608 #include "undef_data.h"
609
610 /*/
611         client_getln(buf->QRname, sizeof buf->QRname);
612         client_getln(buf->QRpasswd, sizeof buf->QRpasswd);
613         client_getln(cbuf, sizeof cbuf);        buf->QRroomaide = atol(cbuf);
614         client_getln(cbuf, sizeof cbuf);        buf->QRhighest = atol(cbuf);
615         client_getln(cbuf, sizeof cbuf);        buf->QRgen = atol(cbuf);
616         client_getln(cbuf, sizeof cbuf);        buf->QRflags = atoi(cbuf);
617         client_getln(buf->QRdirname, sizeof buf->QRdirname);
618         client_getln(cbuf, sizeof cbuf);        buf->QRinfo = atol(cbuf);
619         client_getln(cbuf, sizeof cbuf);        buf->QRfloor = atoi(cbuf);
620         client_getln(cbuf, sizeof cbuf);        buf->QRmtime = atol(cbuf);
621         client_getln(cbuf, sizeof cbuf);        buf->QRep.expire_mode = atoi(cbuf);
622         client_getln(cbuf, sizeof cbuf);        buf->QRep.expire_value = atoi(cbuf);
623         client_getln(cbuf, sizeof cbuf);        buf->QRnumber = atol(cbuf);
624         client_getln(cbuf, sizeof cbuf);        buf->QRorder = atoi(cbuf);
625         client_getln(cbuf, sizeof cbuf);        buf->QRflags2 = atoi(cbuf);
626         client_getln(cbuf, sizeof cbuf);        buf->QRdefaultview = atoi(cbuf);
627 //*/
628         putroom(buf);
629         CtdlLogPrintf(CTDL_INFO, "Imported room <%s>\n", qrbuf.QRname);
630         /* format of message list export is all message numbers output
631          * one per line terminated by a 0.
632          */
633         while ((client_getln(cbuf, sizeof cbuf) >= 0) && (msgnum = atol(cbuf))) {
634                 CtdlSaveMsgPointerInRoom(qrbuf.QRname, msgnum, 0, NULL);
635                 cprintdot(iterations);
636                 ++msgcount;
637                 if (CtdlThreadCheckStop())
638                         break;
639         }
640         CtdlLogPrintf(CTDL_INFO, "(%d messages)\n", msgcount);
641 }
642
643
644 void artv_import_floor(void) {
645         struct floor flbuf, *buf;
646         int i;
647         char cbuf[SIZ];
648
649         buf = & flbuf;
650         memset(buf, 0, sizeof(buf));
651         client_getln(cbuf, sizeof cbuf);        i = atoi(cbuf);
652 /*
653 #include "artv_deserialize.h"
654 #include "dtds/floor-defs.h"
655 #include "undef_data.h"
656 /*/
657         client_getln(cbuf, sizeof cbuf);        buf->f_flags = atoi(cbuf);
658         client_getln(buf->f_name, sizeof buf->f_name);
659         client_getln(cbuf, sizeof cbuf);        buf->f_ref_count = atoi(cbuf);
660         client_getln(cbuf, sizeof cbuf);        buf->f_ep.expire_mode = atoi(cbuf);
661         client_getln(cbuf, sizeof cbuf);        buf->f_ep.expire_value = atoi(cbuf);
662 //*/
663         putfloor(buf, i);
664         CtdlLogPrintf(CTDL_INFO, "Imported floor #%d (%s)\n", i, flbuf.f_name);
665 }
666
667
668 /* 
669  */
670 void artv_import_visit(void) {
671         struct visit vbuf;
672         char buf[SIZ];
673         int i;
674         int is_textual_seen = 0;
675
676         client_getln(buf, sizeof buf);  vbuf.v_roomnum = atol(buf);
677         client_getln(buf, sizeof buf);  vbuf.v_roomgen = atol(buf);
678         client_getln(buf, sizeof buf);  vbuf.v_usernum = atol(buf);
679
680         client_getln(buf, sizeof buf);
681         vbuf.v_lastseen = atol(buf);
682         for (i=0; buf[i]; ++i) if (!isdigit(buf[i])) is_textual_seen = 1;
683         if (is_textual_seen)    strcpy(vbuf.v_seen, buf);
684
685         client_getln(vbuf.v_answered, sizeof vbuf.v_answered);
686         client_getln(buf, sizeof buf);  vbuf.v_flags = atoi(buf);
687         client_getln(buf, sizeof buf);  vbuf.v_view = atoi(buf);
688         put_visit(&vbuf);
689         CtdlLogPrintf(CTDL_INFO, "Imported visit %ld/%ld/%ld\n",
690                 vbuf.v_roomnum, vbuf.v_roomgen, vbuf.v_usernum);
691 }
692
693
694
695 void artv_import_message(long *iterations, char **b64buf, size_t *b64size, char **plain, size_t *plain_size) {
696         struct MetaData smi;
697         long msgnum;
698         long msglen;
699         char buf[SIZ];
700         size_t b64len = 0;
701         char *tbuf, *tbuf2;
702         size_t mlen;
703         
704         memset(&smi, 0, sizeof(struct MetaData));
705         client_getln(buf, sizeof buf);  msgnum = atol(buf);
706                                 smi.meta_msgnum = msgnum;
707         client_getln(buf, sizeof buf);  smi.meta_refcount = atoi(buf);
708         client_getln(smi.meta_content_type, sizeof smi.meta_content_type);
709
710         CtdlLogPrintf(CTDL_INFO, "message #%ld\n", msgnum);
711
712         /* decode base64 message text */
713         while (client_getln(buf, sizeof buf) >= 0 && strcasecmp(buf, END_OF_MESSAGE)) {
714                 if (CtdlThreadCheckStop())
715                         return;
716                         
717                 cprintdot(iterations);
718                 
719                 /**
720                  * Grow the buffers if we need to
721                  */
722                 mlen = strlen (buf);
723                 if (b64len + mlen > *b64size)
724                 {
725                         tbuf = realloc (*b64buf, *b64size + SIZ);
726                         tbuf2 = realloc (*plain, *plain_size + SIZ);
727                         if (tbuf && tbuf2)
728                         {
729                                 *b64buf = tbuf;
730                                 *plain = tbuf2;
731                                 *b64size += SIZ;
732                                 *plain_size += SIZ;
733                         }
734                         else
735                         {
736                                 CtdlLogPrintf(CTDL_DEBUG, "ARTV import: realloc() failed.\n");
737                                 cprintf("\nMemory allocation failure.\n");
738                                 return;
739                         }
740                 }
741                 strcat (*b64buf, buf);
742                 b64len += mlen;
743         }
744         
745         /**
746          * FIXME: This is an ideal place for a "sub thread". What we should do is create a new thread
747          * This new thread would be given the base64 encoded message, it would then decode it and store
748          * it. This would allow the thread that is reading from the client to continue doing so, basically
749          * backgrounding the decode and store operation. This would increase the speed of the import from
750          * the users perspective.
751          */
752         
753         /**
754          * Decode and store the message
755          * If this decode and store takes more than 5 seconds the sendcommand WD timer may expire.
756          */
757         msglen = CtdlDecodeBase64(*plain, *b64buf, b64len);
758         CtdlLogPrintf(CTDL_DEBUG, "msglen = %ld\n", msglen);
759         cdb_store(CDB_MSGMAIN, &msgnum, sizeof(long), *plain, msglen);
760         PutMetaData(&smi);
761         CtdlLogPrintf(CTDL_INFO, "Imported message %ld\n", msgnum);
762         
763 }
764
765
766
767
768 void artv_do_import(void) {
769         char buf[SIZ];
770         char abuf[SIZ];
771         char s_version[SIZ];
772         int version;
773         long iterations;
774         char *b64mes = NULL;
775         char *plain = NULL;
776         size_t b64size, plain_size;
777         
778         unbuffer_output();
779
780         /* Prepare buffers for base 64 decoding of messages.
781         */
782         b64mes = malloc(SIZ);
783         if (b64mes == NULL)
784         {
785                 cprintf("%d Malloc failed in import/export.\n",
786                         ERROR + RESOURCE_BUSY);
787                 return;
788         }
789         b64mes[0] = 0;
790         b64size=SIZ;
791         plain = malloc(SIZ);
792         if (plain == NULL)
793         {
794                 cprintf("%d Malloc failed in import/export.\n",
795                         ERROR + RESOURCE_BUSY);
796                 free(b64mes);
797                 return;
798         }
799         plain[0] = 0;
800         plain_size = SIZ;
801         
802         cprintf("%d sock it to me\n", SEND_LISTING);
803         abuf[0] = '\0';
804         unbuffer_output();
805         iterations = 0;
806         while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) {
807                 if (CtdlThreadCheckStop())
808                         break;  // Should we break or return?
809                 
810                 if (buf[0] == '\0')
811                         continue;
812                         
813                 CtdlLogPrintf(CTDL_DEBUG, "import keyword: <%s>\n", buf);
814                 if ((abuf[0] == '\0') || (strcasecmp(buf, abuf))) {
815                         cprintf ("\n\nImporting datatype %s\n", buf);
816                         strncpy (abuf, buf, SIZ);       
817                         iterations = 0;
818                 }
819                 else {
820                         cprintdot(&iterations);
821                 }
822                 
823                 if (!strcasecmp(buf, "version")) {
824                         client_getln(s_version, sizeof s_version);
825                         version = atoi(s_version);
826                         if ((version<EXPORT_REV_MIN) || (version>REV_LEVEL)) {
827                                 CtdlLogPrintf(CTDL_ERR, "Version mismatch in ARTV import; aborting\n");
828                                 break;
829                         }
830                 }
831                 else if (!strcasecmp(buf, "config")) artv_import_config();
832                 else if (!strcasecmp(buf, "control")) artv_import_control();
833                 else if (!strcasecmp(buf, "user")) artv_import_user();
834                 else if (!strcasecmp(buf, "room")) artv_import_room(&iterations);
835                 else if (!strcasecmp(buf, "floor")) artv_import_floor();
836                 else if (!strcasecmp(buf, "visit")) artv_import_visit();
837                 else if (!strcasecmp(buf, "message"))
838                 {
839                         b64mes[0] = 0;
840                         plain[0] = 0;
841                         artv_import_message(&iterations, &b64mes, &b64size, &plain, &plain_size);
842                 }
843                 else break;
844         }
845         free (b64mes);
846         free (plain);
847         
848         CtdlLogPrintf(CTDL_INFO, "Invalid keyword <%s>.  Flushing input.\n", buf);
849         while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000"))  ;;
850         rebuild_euid_index();
851         rebuild_usersbynumber();
852 }
853
854
855
856 void cmd_artv(char *cmdbuf) {
857         char cmd[32];
858         static int is_running = 0;
859
860         if (CtdlAccessCheck(ac_internal)) return;
861         if (is_running) {
862                 cprintf("%d The importer/exporter is already running.\n",
863                         ERROR + RESOURCE_BUSY);
864                 return;
865         }
866         is_running = 1;
867
868         CtdlMakeTempFileName(artv_tempfilename1, sizeof artv_tempfilename1);
869         CtdlMakeTempFileName(artv_tempfilename2, sizeof artv_tempfilename2);
870
871         extract_token(cmd, cmdbuf, 0, '|', sizeof cmd);
872         if (!strcasecmp(cmd, "export")) artv_do_export();
873         else if (!strcasecmp(cmd, "import")) artv_do_import();
874         else if (!strcasecmp(cmd, "dump")) artv_do_dump();
875         else cprintf("%d illegal command\n", ERROR + ILLEGAL_VALUE);
876
877         unlink(artv_tempfilename1);
878         unlink(artv_tempfilename2);
879
880         is_running = 0;
881 }
882
883
884
885
886 CTDL_MODULE_INIT(vandelay)
887 {
888         if (!threading)
889         {
890                 CtdlRegisterProtoHook(cmd_artv, "ARTV", "import/export data store");
891         }
892         
893         /* return our Subversion id for the Log */
894         return "$Id$";
895 }