]> code.citadel.org Git - citadel.git/blob - citadel/modules/vandelay/serv_vandelay.c
Completed artv import/export of openids
[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_openids(void) {
403         struct cdbdata *cdboi;
404         long usernum;
405
406         cdb_rewind(CDB_OPENID);
407         while (cdboi = cdb_next_item(CDB_OPENID), cdboi != NULL) {
408                 if (cdboi->len > sizeof(long)) {
409                         client_write("openid\n", 7);
410                         memcpy(&usernum, cdboi->ptr, sizeof(long));
411                         cprintf("%s\n", (cdboi->ptr)+sizeof(long) );
412                         cprintf("%ld\n", usernum);
413                 }
414                 cdb_free(cdboi);
415         }
416 }
417
418
419
420
421 void artv_export_messages(void) {
422         char buf[SIZ];
423         long msgnum;
424         int count = 0;
425         t_context *Ctx;
426
427         Ctx = CC;
428         artv_global_message_list = fopen(artv_tempfilename1, "r");
429         if (artv_global_message_list != NULL) {
430                 CtdlLogPrintf(CTDL_INFO, "Opened %s\n", artv_tempfilename1);
431                 while ((Ctx->kill_me != 1) && 
432                        (fgets(buf, sizeof(buf), artv_global_message_list) != NULL)) {
433                         msgnum = atol(buf);
434                         if (msgnum > 0L) {
435                                 artv_export_message(msgnum);
436                                 ++count;
437                         }
438                 }
439                 fclose(artv_global_message_list);
440         }
441         if (Ctx->kill_me != 1)
442                 CtdlLogPrintf(CTDL_INFO, "Exported %d messages.\n", count);
443         else
444                 CtdlLogPrintf(CTDL_ERR, "Export aborted due to client disconnect! \n");
445 }
446
447 void artv_dump_messages(void) {
448         char buf[SIZ];
449         long msgnum;
450         int count = 0;
451         t_context *Ctx;
452
453         Ctx = CC;
454         artv_global_message_list = fopen(artv_tempfilename1, "r");
455         if (artv_global_message_list != NULL) {
456                 CtdlLogPrintf(CTDL_INFO, "Opened %s\n", artv_tempfilename1);
457                 while ((Ctx->kill_me != 1) && 
458                        (fgets(buf, sizeof(buf), artv_global_message_list) != NULL)) {
459                         msgnum = atol(buf);
460                         if (msgnum > 0L) {
461                                 artv_dump_message(msgnum);
462                                 ++count;
463                         }
464                 }
465                 fclose(artv_global_message_list);
466         }
467         if (Ctx->kill_me != 1)
468                 CtdlLogPrintf(CTDL_INFO, "Exported %d messages.\n", count);
469         else
470                 CtdlLogPrintf(CTDL_ERR, "Export aborted due to client disconnect! \n");
471 }
472
473
474
475
476 void artv_do_export(void) {
477         struct config *buf;
478         buf = &config;
479         t_context *Ctx;
480
481         Ctx = CC;
482         cprintf("%d Exporting all Citadel databases.\n", LISTING_FOLLOWS);
483
484         cprintf("version\n%d\n", REV_LEVEL);
485
486         /* export the config file (this is done using x-macros) */
487         client_write("config\n", 7);
488
489 #include "artv_serialize.h"
490 #include "dtds/config-defs.h"
491 #include "undef_data.h"
492         client_write("\n", 1);
493         
494         /* Export the control file */
495         get_control();
496         client_write("control\n", 8);
497         cprintf("%ld\n", CitControl.MMhighest);
498         cprintf("%u\n", CitControl.MMflags);
499         cprintf("%ld\n", CitControl.MMnextuser);
500         cprintf("%ld\n", CitControl.MMnextroom);
501         cprintf("%d\n", CitControl.version);
502         if (Ctx->kill_me != 1)
503                 artv_export_users();
504         if (Ctx->kill_me != 1)
505                 artv_export_openids();
506         if (Ctx->kill_me != 1)
507                 artv_export_rooms();
508         if (Ctx->kill_me != 1)
509                 artv_export_floors();
510         if (Ctx->kill_me != 1)
511                 artv_export_visits();
512         if (Ctx->kill_me != 1)
513                 artv_export_messages();
514         client_write("000\n", 4);
515 }
516
517 void artv_do_dump(void) {
518         struct config *buf;
519         buf = &config;
520         t_context *Ctx;
521
522         Ctx = CC;
523         cprintf("%d dumping Citadel structures.\n", LISTING_FOLLOWS);
524
525         cprintf("version\n%d\n", REV_LEVEL);
526
527         /* export the config file (this is done using x-macros) */
528         client_write("config\n", 7);
529
530 #include "artv_dump.h"
531 #include "dtds/config-defs.h"
532 #include "undef_data.h"
533
534         /* Export the control file */
535         get_control();
536         client_write("control\n", 8);
537         cprintf(" MMhighest: %ld\n", CitControl.MMhighest);
538         cprintf(" MMflags: %u\n", CitControl.MMflags);
539         cprintf(" MMnextuser: %ld\n", CitControl.MMnextuser);
540         cprintf(" MMnextroom: %ld\n", CitControl.MMnextroom);
541         cprintf(" version: %d\n\n", CitControl.version);
542         if (Ctx->kill_me != 1)
543                 artv_dump_users();
544         if (Ctx->kill_me != 1)
545                 artv_dump_rooms();
546         if (Ctx->kill_me != 1)
547                 artv_dump_floors();
548         if (Ctx->kill_me != 1)
549                 artv_dump_visits();
550         if (Ctx->kill_me != 1)
551                 artv_dump_messages();
552
553         client_write("000\n", 4);
554 }
555
556
557
558 void artv_import_config(void) {
559         char cbuf[SIZ];
560         struct config *buf;
561         buf = &config;
562
563         CtdlLogPrintf(CTDL_DEBUG, "Importing config file\n");
564
565 #include "artv_deserialize.h"
566 #include "dtds/config-defs.h"
567 #include "undef_data.h"
568
569         config.c_enable_fulltext = 0;   /* always disable */
570         put_config();
571         CtdlLogPrintf(CTDL_INFO, "Imported config file\n");
572 }
573
574
575 void artv_import_control(void) {
576         char buf[SIZ];
577
578         CtdlLogPrintf(CTDL_DEBUG, "Importing control file\n");
579         client_getln(buf, sizeof buf);  CitControl.MMhighest = atol(buf);
580         client_getln(buf, sizeof buf);  CitControl.MMflags = atoi(buf);
581         client_getln(buf, sizeof buf);  CitControl.MMnextuser = atol(buf);
582         client_getln(buf, sizeof buf);  CitControl.MMnextroom = atol(buf);
583         client_getln(buf, sizeof buf);  CitControl.version = atoi(buf);
584         CitControl.MMfulltext = (-1L);  /* always flush */
585         put_control();
586         CtdlLogPrintf(CTDL_INFO, "Imported control file\n");
587 }
588
589
590 void artv_import_user(void) {
591         char cbuf[SIZ];
592         struct ctdluser usbuf, *buf;
593         buf = &usbuf;
594 /*
595 #include "artv_deserialize.h"
596 #include "dtds/user-defs.h"
597 #include "undef_data.h"
598
599 /*/
600         client_getln(cbuf, sizeof cbuf);        buf->version = atoi(cbuf);
601         client_getln(cbuf, sizeof cbuf);        buf->uid = atoi(cbuf);
602         client_getln(buf->password, sizeof buf->password);
603         client_getln(cbuf, sizeof cbuf);        buf->flags = atoi(cbuf);
604         client_getln(cbuf, sizeof cbuf);        buf->timescalled = atol(cbuf);
605         client_getln(cbuf, sizeof cbuf);        buf->posted = atol(cbuf);
606         client_getln(cbuf, sizeof cbuf);        buf->axlevel = atoi(cbuf);
607         client_getln(cbuf, sizeof cbuf);        buf->usernum = atol(cbuf);
608         client_getln(cbuf, sizeof cbuf);        buf->lastcall = atol(cbuf);
609         client_getln(cbuf, sizeof cbuf);        buf->USuserpurge = atoi(cbuf);
610         client_getln(buf->fullname, sizeof buf->fullname);
611         client_getln(cbuf, sizeof cbuf);        buf->USscreenwidth = atoi(cbuf);
612         client_getln(cbuf, sizeof cbuf);        buf->USscreenheight = atoi(cbuf);
613 //*/
614         putuser(buf);
615 }
616
617
618 void artv_import_room(long *iterations) {
619         char cbuf[SIZ];
620         struct ctdlroom qrbuf, *buf;
621         long msgnum;
622         int msgcount = 0;
623
624         buf = &qrbuf;
625 /*
626 #include "artv_deserialize.h"
627 #include "dtds/room-defs.h"
628 #include "undef_data.h"
629
630 /*/
631         client_getln(buf->QRname, sizeof buf->QRname);
632         client_getln(buf->QRpasswd, sizeof buf->QRpasswd);
633         client_getln(cbuf, sizeof cbuf);        buf->QRroomaide = atol(cbuf);
634         client_getln(cbuf, sizeof cbuf);        buf->QRhighest = atol(cbuf);
635         client_getln(cbuf, sizeof cbuf);        buf->QRgen = atol(cbuf);
636         client_getln(cbuf, sizeof cbuf);        buf->QRflags = atoi(cbuf);
637         client_getln(buf->QRdirname, sizeof buf->QRdirname);
638         client_getln(cbuf, sizeof cbuf);        buf->QRinfo = atol(cbuf);
639         client_getln(cbuf, sizeof cbuf);        buf->QRfloor = atoi(cbuf);
640         client_getln(cbuf, sizeof cbuf);        buf->QRmtime = atol(cbuf);
641         client_getln(cbuf, sizeof cbuf);        buf->QRep.expire_mode = atoi(cbuf);
642         client_getln(cbuf, sizeof cbuf);        buf->QRep.expire_value = atoi(cbuf);
643         client_getln(cbuf, sizeof cbuf);        buf->QRnumber = atol(cbuf);
644         client_getln(cbuf, sizeof cbuf);        buf->QRorder = atoi(cbuf);
645         client_getln(cbuf, sizeof cbuf);        buf->QRflags2 = atoi(cbuf);
646         client_getln(cbuf, sizeof cbuf);        buf->QRdefaultview = atoi(cbuf);
647 //*/
648         putroom(buf);
649         CtdlLogPrintf(CTDL_INFO, "Imported room <%s>\n", qrbuf.QRname);
650         /* format of message list export is all message numbers output
651          * one per line terminated by a 0.
652          */
653         while ((client_getln(cbuf, sizeof cbuf) >= 0) && (msgnum = atol(cbuf))) {
654                 CtdlSaveMsgPointerInRoom(qrbuf.QRname, msgnum, 0, NULL);
655                 cprintdot(iterations);
656                 ++msgcount;
657                 if (CtdlThreadCheckStop())
658                         break;
659         }
660         CtdlLogPrintf(CTDL_INFO, "(%d messages)\n", msgcount);
661 }
662
663
664 void artv_import_floor(void) {
665         struct floor flbuf, *buf;
666         int i;
667         char cbuf[SIZ];
668
669         buf = & flbuf;
670         memset(buf, 0, sizeof(buf));
671         client_getln(cbuf, sizeof cbuf);        i = atoi(cbuf);
672 /*
673 #include "artv_deserialize.h"
674 #include "dtds/floor-defs.h"
675 #include "undef_data.h"
676 /*/
677         client_getln(cbuf, sizeof cbuf);        buf->f_flags = atoi(cbuf);
678         client_getln(buf->f_name, sizeof buf->f_name);
679         client_getln(cbuf, sizeof cbuf);        buf->f_ref_count = atoi(cbuf);
680         client_getln(cbuf, sizeof cbuf);        buf->f_ep.expire_mode = atoi(cbuf);
681         client_getln(cbuf, sizeof cbuf);        buf->f_ep.expire_value = atoi(cbuf);
682 //*/
683         putfloor(buf, i);
684         CtdlLogPrintf(CTDL_INFO, "Imported floor #%d (%s)\n", i, flbuf.f_name);
685 }
686
687
688 void artv_import_visit(void) {
689         struct visit vbuf;
690         char buf[SIZ];
691         int i;
692         int is_textual_seen = 0;
693
694         client_getln(buf, sizeof buf);  vbuf.v_roomnum = atol(buf);
695         client_getln(buf, sizeof buf);  vbuf.v_roomgen = atol(buf);
696         client_getln(buf, sizeof buf);  vbuf.v_usernum = atol(buf);
697
698         client_getln(buf, sizeof buf);
699         vbuf.v_lastseen = atol(buf);
700         for (i=0; buf[i]; ++i) if (!isdigit(buf[i])) is_textual_seen = 1;
701         if (is_textual_seen)    strcpy(vbuf.v_seen, buf);
702
703         client_getln(vbuf.v_answered, sizeof vbuf.v_answered);
704         client_getln(buf, sizeof buf);  vbuf.v_flags = atoi(buf);
705         client_getln(buf, sizeof buf);  vbuf.v_view = atoi(buf);
706         put_visit(&vbuf);
707         CtdlLogPrintf(CTDL_INFO, "Imported visit %ld/%ld/%ld\n",
708                 vbuf.v_roomnum, vbuf.v_roomgen, vbuf.v_usernum);
709 }
710
711
712 void artv_import_openid(void) {
713         char buf[SIZ];
714         long usernum;
715         char openid[1024];
716         char *data;
717         int data_len;
718
719         client_getln(openid, sizeof openid);
720         client_getln(buf, sizeof buf);  usernum = atol(buf);
721         if (IsEmptyStr(openid)) return;
722
723         data_len = sizeof(long) + strlen(openid) + 1;
724         data = malloc(data_len);
725
726         memcpy(data, &usernum, sizeof(long));
727         memcpy(&data[sizeof(long)], openid, strlen(openid) + 1);
728
729         cdb_store(CDB_OPENID, openid, strlen(openid), data, data_len);
730         free(data);
731
732         CtdlLogPrintf(CTDL_INFO, "Imported OpenID %s for user #%ld\n", openid, usernum);
733 }
734
735
736 void artv_import_message(long *iterations, char **b64buf, size_t *b64size, char **plain, size_t *plain_size) {
737         struct MetaData smi;
738         long msgnum;
739         long msglen;
740         char buf[SIZ];
741         size_t b64len = 0;
742         char *tbuf, *tbuf2;
743         size_t mlen;
744         
745         memset(&smi, 0, sizeof(struct MetaData));
746         client_getln(buf, sizeof buf);  msgnum = atol(buf);
747                                 smi.meta_msgnum = msgnum;
748         client_getln(buf, sizeof buf);  smi.meta_refcount = atoi(buf);
749         client_getln(smi.meta_content_type, sizeof smi.meta_content_type);
750
751         CtdlLogPrintf(CTDL_INFO, "message #%ld\n", msgnum);
752
753         /* decode base64 message text */
754         while (client_getln(buf, sizeof buf) >= 0 && strcasecmp(buf, END_OF_MESSAGE)) {
755                 if (CtdlThreadCheckStop())
756                         return;
757                         
758                 cprintdot(iterations);
759                 
760                 /**
761                  * Grow the buffers if we need to
762                  */
763                 mlen = strlen (buf);
764                 if (b64len + mlen > *b64size)
765                 {
766                         tbuf = realloc (*b64buf, *b64size + SIZ);
767                         tbuf2 = realloc (*plain, *plain_size + SIZ);
768                         if (tbuf && tbuf2)
769                         {
770                                 *b64buf = tbuf;
771                                 *plain = tbuf2;
772                                 *b64size += SIZ;
773                                 *plain_size += SIZ;
774                         }
775                         else
776                         {
777                                 CtdlLogPrintf(CTDL_DEBUG, "ARTV import: realloc() failed.\n");
778                                 cprintf("\nMemory allocation failure.\n");
779                                 return;
780                         }
781                 }
782                 strcat (*b64buf, buf);
783                 b64len += mlen;
784         }
785         
786         /**
787          * FIXME: This is an ideal place for a "sub thread". What we should do is create a new thread
788          * This new thread would be given the base64 encoded message, it would then decode it and store
789          * it. This would allow the thread that is reading from the client to continue doing so, basically
790          * backgrounding the decode and store operation. This would increase the speed of the import from
791          * the users perspective.
792          */
793         
794         /**
795          * Decode and store the message
796          * If this decode and store takes more than 5 seconds the sendcommand WD timer may expire.
797          */
798         msglen = CtdlDecodeBase64(*plain, *b64buf, b64len);
799         CtdlLogPrintf(CTDL_DEBUG, "msglen = %ld\n", msglen);
800         cdb_store(CDB_MSGMAIN, &msgnum, sizeof(long), *plain, msglen);
801         PutMetaData(&smi);
802         CtdlLogPrintf(CTDL_INFO, "Imported message %ld\n", msgnum);
803         
804 }
805
806
807
808
809 void artv_do_import(void) {
810         char buf[SIZ];
811         char abuf[SIZ];
812         char s_version[SIZ];
813         int version;
814         long iterations;
815         char *b64mes = NULL;
816         char *plain = NULL;
817         size_t b64size, plain_size;
818         
819         unbuffer_output();
820
821         /* Prepare buffers for base 64 decoding of messages.
822         */
823         b64mes = malloc(SIZ);
824         if (b64mes == NULL)
825         {
826                 cprintf("%d Malloc failed in import/export.\n",
827                         ERROR + RESOURCE_BUSY);
828                 return;
829         }
830         b64mes[0] = 0;
831         b64size=SIZ;
832         plain = malloc(SIZ);
833         if (plain == NULL)
834         {
835                 cprintf("%d Malloc failed in import/export.\n",
836                         ERROR + RESOURCE_BUSY);
837                 free(b64mes);
838                 return;
839         }
840         plain[0] = 0;
841         plain_size = SIZ;
842         
843         cprintf("%d sock it to me\n", SEND_LISTING);
844         abuf[0] = '\0';
845         unbuffer_output();
846         iterations = 0;
847         while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) {
848                 if (CtdlThreadCheckStop())
849                         break;  // Should we break or return?
850                 
851                 if (buf[0] == '\0')
852                         continue;
853                         
854                 CtdlLogPrintf(CTDL_DEBUG, "import keyword: <%s>\n", buf);
855                 if ((abuf[0] == '\0') || (strcasecmp(buf, abuf))) {
856                         cprintf ("\n\nImporting datatype %s\n", buf);
857                         strncpy (abuf, buf, SIZ);       
858                         iterations = 0;
859                 }
860                 else {
861                         cprintdot(&iterations);
862                 }
863                 
864                 if (!strcasecmp(buf, "version")) {
865                         client_getln(s_version, sizeof s_version);
866                         version = atoi(s_version);
867                         if ((version<EXPORT_REV_MIN) || (version>REV_LEVEL)) {
868                                 CtdlLogPrintf(CTDL_ERR, "Version mismatch in ARTV import; aborting\n");
869                                 break;
870                         }
871                 }
872                 else if (!strcasecmp(buf, "config")) artv_import_config();
873                 else if (!strcasecmp(buf, "control")) artv_import_control();
874                 else if (!strcasecmp(buf, "user")) artv_import_user();
875                 else if (!strcasecmp(buf, "room")) artv_import_room(&iterations);
876                 else if (!strcasecmp(buf, "floor")) artv_import_floor();
877                 else if (!strcasecmp(buf, "visit")) artv_import_visit();
878                 else if (!strcasecmp(buf, "openid")) artv_import_openid();
879                 else if (!strcasecmp(buf, "message"))
880                 {
881                         b64mes[0] = 0;
882                         plain[0] = 0;
883                         artv_import_message(&iterations, &b64mes, &b64size, &plain, &plain_size);
884                 }
885                 else break;
886         }
887         free (b64mes);
888         free (plain);
889         
890         CtdlLogPrintf(CTDL_INFO, "Invalid keyword <%s>.  Flushing input.\n", buf);
891         while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000"))  ;;
892         rebuild_euid_index();
893         rebuild_usersbynumber();
894 }
895
896
897
898 void cmd_artv(char *cmdbuf) {
899         char cmd[32];
900         static int is_running = 0;
901
902         if (CtdlAccessCheck(ac_internal)) return;
903         if (is_running) {
904                 cprintf("%d The importer/exporter is already running.\n",
905                         ERROR + RESOURCE_BUSY);
906                 return;
907         }
908         is_running = 1;
909
910         CtdlMakeTempFileName(artv_tempfilename1, sizeof artv_tempfilename1);
911         CtdlMakeTempFileName(artv_tempfilename2, sizeof artv_tempfilename2);
912
913         extract_token(cmd, cmdbuf, 0, '|', sizeof cmd);
914         if (!strcasecmp(cmd, "export")) artv_do_export();
915         else if (!strcasecmp(cmd, "import")) artv_do_import();
916         else if (!strcasecmp(cmd, "dump")) artv_do_dump();
917         else cprintf("%d illegal command\n", ERROR + ILLEGAL_VALUE);
918
919         unlink(artv_tempfilename1);
920         unlink(artv_tempfilename2);
921
922         is_running = 0;
923 }
924
925
926
927
928 CTDL_MODULE_INIT(vandelay)
929 {
930         if (!threading)
931         {
932                 CtdlRegisterProtoHook(cmd_artv, "ARTV", "import/export data store");
933         }
934         
935         /* return our Subversion id for the Log */
936         return "$Id$";
937 }