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