citadel
About: Citadel is an advanced messaging and collaboration system for groupware and BBS applications (preferred OS: Linux).
  Fossies Dox: citadel.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

serv_migrate.c
Go to the documentation of this file.
1// This module dumps and/or loads the Citadel database in XML format.
2//
3// Copyright (c) 1987-2021 by the citadel.org team
4//
5// This program is open source software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License version 3.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// Explanation of <progress> tags:
14//
15// 0% started
16// 2% finished exporting configuration
17// 7% finished exporting users
18// 12% finished exporting openids
19// 17% finished exporting rooms
20// 18% finished exporting floors
21// 25% finished exporting visits
22// 26-99% exporting messages
23// 100% finished exporting messages
24//
25// These tags are inserted into the XML stream to give the reader an approximation of its progress.
26
27#include "sysdep.h"
28#include <stdlib.h>
29#include <unistd.h>
30#include <stdio.h>
31#include <fcntl.h>
32#include <signal.h>
33#include <pwd.h>
34#include <errno.h>
35#include <sys/types.h>
36#include <time.h>
37#include <sys/wait.h>
38#include <string.h>
39#include <ctype.h>
40#include <limits.h>
41#include <expat.h>
42#include <libcitadel.h>
43#include "citadel.h"
44#include "server.h"
45#include "citserver.h"
46#include "support.h"
47#include "config.h"
48#include "database.h"
49#include "msgbase.h"
50#include "user_ops.h"
51#include "euidindex.h"
52#include "ctdl_module.h"
53
54char migr_tempfilename1[PATH_MAX];
55char migr_tempfilename2[PATH_MAX];
57int total_msgs = 0;
58char *ikey = NULL; // If we're importing a config key we store it here.
59
60//*****************************************************************************
61//* Code which implements the export appears in this section *
62//*****************************************************************************
63
64// Output a string to the client with these characters escaped: & < > " '
65void xml_strout(char *str) {
66
67 char *c = str;
68
69 if (str == NULL) {
70 return;
71 }
72
73 while (*c != 0) {
74 if (*c == '\"') {
75 client_write(HKEY("&quot;"));
76 }
77 else if (*c == '\'') {
78 client_write(HKEY("&apos;"));
79 }
80 else if (*c == '<') {
81 client_write(HKEY("&lt;"));
82 }
83 else if (*c == '>') {
84 client_write(HKEY("&gt;"));
85 }
86 else if (*c == '&') {
87 client_write(HKEY("&amp;"));
88 }
89 else {
90 client_write(c, 1);
91 }
92 ++c;
93 }
94}
95
96
97// Export a user record as XML
98void migr_export_users_backend(char *username, void *data) {
99
100 struct ctdluser u;
101 if (CtdlGetUser(&u, username) != 0) {
102 return;
103 }
104
105 client_write(HKEY("<user>\n"));
106 cprintf("<u_version>%d</u_version>\n", u.version);
107 cprintf("<u_uid>%ld</u_uid>\n", (long)u.uid);
108 client_write(HKEY("<u_password>")); xml_strout(u.password); client_write(HKEY("</u_password>\n"));
109 cprintf("<u_flags>%u</u_flags>\n", u.flags);
110 cprintf("<u_timescalled>%ld</u_timescalled>\n", u.timescalled);
111 cprintf("<u_posted>%ld</u_posted>\n", u.posted);
112 cprintf("<u_axlevel>%d</u_axlevel>\n", u.axlevel);
113 cprintf("<u_usernum>%ld</u_usernum>\n", u.usernum);
114 cprintf("<u_lastcall>%ld</u_lastcall>\n", (long)u.lastcall);
115 cprintf("<u_USuserpurge>%d</u_USuserpurge>\n", u.USuserpurge);
116 client_write(HKEY("<u_fullname>")); xml_strout(u.fullname); client_write(HKEY("</u_fullname>\n"));
117 cprintf("<u_msgnum_bio>%ld</u_msgnum_bio>\n", u.msgnum_bio);
118 cprintf("<u_msgnum_pic>%ld</u_msgnum_pic>\n", u.msgnum_pic);
119 cprintf("<u_emailaddrs>%s</u_emailaddrs>\n", u.emailaddrs);
120 cprintf("<u_msgnum_inboxrules>%ld</u_msgnum_inboxrules>\n", u.msgnum_inboxrules);
121 cprintf("<u_lastproc_inboxrules>%ld</u_lastproc_inboxrules>\n", u.lastproc_inboxrules);
122 client_write(HKEY("</user>\n"));
123}
124
125
128}
129
130
131void migr_export_room_msg(long msgnum, void *userdata) {
132 static int count = 0;
133
134 cprintf("%ld,", msgnum);
135 if (++count%10==0) {
136 cprintf("\n");
137 }
138 fprintf(migr_global_message_list, "%ld\n", msgnum);
139}
140
141
142void migr_export_rooms_backend(struct ctdlroom *buf, void *data) {
143 client_write(HKEY("<room>\n"));
144 client_write(HKEY("<QRname>"));
145 xml_strout(buf->QRname);
146 client_write(HKEY("</QRname>\n"));
147 client_write(HKEY("<QRpasswd>"));
148 xml_strout(buf->QRpasswd);
149 client_write(HKEY("</QRpasswd>\n"));
150 cprintf("<QRroomaide>%ld</QRroomaide>\n", buf->QRroomaide);
151 cprintf("<QRhighest>%ld</QRhighest>\n", buf->QRhighest);
152 cprintf("<QRgen>%ld</QRgen>\n", (long)buf->QRgen);
153 cprintf("<QRflags>%u</QRflags>\n", buf->QRflags);
154 if (buf->QRflags & QR_DIRECTORY) {
155 client_write(HKEY("<QRdirname>"));
156 xml_strout(buf->QRdirname);
157 client_write(HKEY("</QRdirname>\n"));
158 }
159 cprintf("<QRfloor>%d</QRfloor>\n", buf->QRfloor);
160 cprintf("<QRmtime>%ld</QRmtime>\n", (long)buf->QRmtime);
161 cprintf("<QRexpire_mode>%d</QRexpire_mode>\n", buf->QRep.expire_mode);
162 cprintf("<QRexpire_value>%d</QRexpire_value>\n", buf->QRep.expire_value);
163 cprintf("<QRnumber>%ld</QRnumber>\n", buf->QRnumber);
164 cprintf("<QRorder>%d</QRorder>\n", buf->QRorder);
165 cprintf("<QRflags2>%u</QRflags2>\n", buf->QRflags2);
166 cprintf("<QRdefaultview>%d</QRdefaultview>\n", buf->QRdefaultview);
167 cprintf("<msgnum_info>%ld</msgnum_info>\n", buf->msgnum_info);
168 cprintf("<msgnum_pic>%ld</msgnum_pic>\n", buf->msgnum_pic);
169 client_write(HKEY("</room>\n"));
170
171 // message list goes inside this tag
172 CtdlGetRoom(&CC->room, buf->QRname);
173 client_write(HKEY("<room_messages>"));
174 client_write(HKEY("<FRname>"));
175 xml_strout(buf->QRname); // buf->QRname rather than CC->room.QRname to guarantee consistency
176 client_write(HKEY("</FRname>\n"));
177 client_write(HKEY("<FRmsglist>\n"));
178 CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, migr_export_room_msg, NULL);
179 client_write(HKEY("</FRmsglist>\n"));
180 client_write(HKEY("</room_messages>\n"));
181}
182
183
185 char cmd[SIZ];
187 if (migr_global_message_list != NULL) {
190 }
191
192 // Process the 'global' message list. (Sort it and remove dups.
193 // Dups are ok because a message may be in more than one room, but
194 // this will be handled by exporting the reference count, not by
195 // exporting the message multiple times.)
196 snprintf(cmd, sizeof cmd, "sort -n <%s >%s", migr_tempfilename1, migr_tempfilename2);
197 if (system(cmd) != 0) {
198 syslog(LOG_ERR, "migrate: error %d", errno);
199 }
200 snprintf(cmd, sizeof cmd, "uniq <%s >%s", migr_tempfilename2, migr_tempfilename1);
201 if (system(cmd) != 0) {
202 syslog(LOG_ERR, "migrate: error %d", errno);
203 }
204
205 snprintf(cmd, sizeof cmd, "wc -l %s", migr_tempfilename1);
206 FILE *fp = popen(cmd, "r");
207 if (fp) {
208 fgets(cmd, sizeof cmd, fp);
209 pclose(fp);
210 total_msgs = atoi(cmd);
211 }
212 else {
213 total_msgs = 1; // any nonzero just to keep it from barfing
214 }
215 syslog(LOG_DEBUG, "migrate: total messages to be exported: %d", total_msgs);
216}
217
218
220 struct floor qfbuf, *buf;
221 int i;
222
223 for (i=0; i < MAXFLOORS; ++i) {
224 client_write(HKEY("<floor>\n"));
225 cprintf("<f_num>%d</f_num>\n", i);
226 CtdlGetFloor(&qfbuf, i);
227 buf = &qfbuf;
228 cprintf("<f_flags>%u</f_flags>\n", buf->f_flags);
229 client_write(HKEY("<f_name>")); xml_strout(buf->f_name); client_write(HKEY("</f_name>\n"));
230 cprintf("<f_ref_count>%d</f_ref_count>\n", buf->f_ref_count);
231 cprintf("<f_ep_expire_mode>%d</f_ep_expire_mode>\n", buf->f_ep.expire_mode);
232 cprintf("<f_ep_expire_value>%d</f_ep_expire_value>\n", buf->f_ep.expire_value);
233 client_write(HKEY("</floor>\n"));
234 }
235}
236
237
238// Return nonzero if the supplied string contains only characters which are valid in a sequence set.
239int is_sequence_set(char *s) {
240 if (!s) return(0);
241
242 char *c = s;
243 char ch;
244 while (ch = *c++, ch) {
245 if (!strchr("0123456789*,:", ch)) {
246 return(0);
247 }
248 }
249 return(1);
250}
251
252
253// Traverse the visits file...
255 visit vbuf;
256 struct cdbdata *cdbv;
257
259
260 while (cdbv = cdb_next_item(CDB_VISIT), cdbv != NULL) {
261 memset(&vbuf, 0, sizeof(visit));
262 memcpy(&vbuf, cdbv->ptr,
263 ((cdbv->len > sizeof(visit)) ?
264 sizeof(visit) : cdbv->len));
265 cdb_free(cdbv);
266
267 client_write(HKEY("<visit>\n"));
268 cprintf("<v_roomnum>%ld</v_roomnum>\n", vbuf.v_roomnum);
269 cprintf("<v_roomgen>%ld</v_roomgen>\n", vbuf.v_roomgen);
270 cprintf("<v_usernum>%ld</v_usernum>\n", vbuf.v_usernum);
271
272 client_write(HKEY("<v_seen>"));
273 if ( (!IsEmptyStr(vbuf.v_seen)) && (is_sequence_set(vbuf.v_seen)) ) {
275 }
276 else {
277 cprintf("%ld", vbuf.v_lastseen);
278 }
279 client_write(HKEY("</v_seen>"));
280
281 if ( (!IsEmptyStr(vbuf.v_answered)) && (is_sequence_set(vbuf.v_answered)) ) {
282 client_write(HKEY("<v_answered>"));
284 client_write(HKEY("</v_answered>\n"));
285 }
286
287 cprintf("<v_flags>%u</v_flags>\n", vbuf.v_flags);
288 cprintf("<v_view>%d</v_view>\n", vbuf.v_view);
289 client_write(HKEY("</visit>\n"));
290 }
291}
292
293
294void migr_export_message(long msgnum) {
295 struct MetaData smi;
296 struct CtdlMessage *msg;
297 struct ser_ret smr;
298 long bytes_written = 0;
299 long this_block = 0;
300
301 // We can use a static buffer here because there will never be more than
302 // one of this operation happening at any given time, and it's really best
303 // to just keep it allocated once instead of torturing malloc/free.
304 // Call this function with msgnum "-1" to free the buffer when finished.
305
306 static int encoded_alloc = 0;
307 static char *encoded_msg = NULL;
308
309 if (msgnum < 0) {
310 if ((encoded_alloc == 0) && (encoded_msg != NULL)) {
311 free(encoded_msg);
312 encoded_alloc = 0;
313 encoded_msg = NULL;
314 }
315 return;
316 }
317
318 // Ok, here we go ...
319
320 msg = CtdlFetchMessage(msgnum, 1);
321 if (msg == NULL) return; // fail silently
322
323 client_write(HKEY("<message>\n"));
324 GetMetaData(&smi, msgnum);
325 cprintf("<msg_msgnum>%ld</msg_msgnum>\n", msgnum);
326 cprintf("<msg_meta_refcount>%d</msg_meta_refcount>\n", smi.meta_refcount);
327 cprintf("<msg_meta_rfc822_length>%ld</msg_meta_rfc822_length>\n", smi.meta_rfc822_length);
328 client_write(HKEY("<msg_meta_content_type>")); xml_strout(smi.meta_content_type); client_write(HKEY("</msg_meta_content_type>\n"));
329
330 client_write(HKEY("<msg_text>"));
331 CtdlSerializeMessage(&smr, msg);
332 CM_Free(msg);
333
334 // Predict the buffer size we need. Expand the buffer if necessary.
335 int encoded_len = smr.len * 15 / 10 ;
336 if (encoded_len > encoded_alloc) {
337 encoded_alloc = encoded_len;
338 encoded_msg = realloc(encoded_msg, encoded_alloc);
339 }
340
341 if (encoded_msg == NULL) {
342 // Questionable hack that hopes it'll work next time and we only lose one message
343 encoded_alloc = 0;
344 }
345 else {
346 // Once we do the encoding we know the exact size
347 encoded_len = CtdlEncodeBase64(encoded_msg, (char *)smr.ser, smr.len, 1);
348
349 // Careful now. If the message is gargantuan, trying to write multiple gigamegs in one
350 // big write operation can make our transport unhappy. So we'll chunk it up 10 KB at a time.
351 bytes_written = 0;
352 while ( (bytes_written < encoded_len) && (!server_shutting_down) ) {
353 this_block = encoded_len - bytes_written;
354 if (this_block > 10240) {
355 this_block = 10240;
356 }
357 client_write(&encoded_msg[bytes_written], this_block);
358 bytes_written += this_block;
359 }
360 }
361
362 free(smr.ser);
363
364 client_write(HKEY("</msg_text>\n"));
365 client_write(HKEY("</message>\n"));
366}
367
368
370 struct cdbdata *cdboi;
371 long usernum;
372 char url[512];
373
375 while (cdboi = cdb_next_item(CDB_EXTAUTH), cdboi != NULL) {
376 if (cdboi->len > sizeof(long)) {
377 client_write(HKEY("<openid>\n"));
378 memcpy(&usernum, cdboi->ptr, sizeof(long));
379 snprintf(url, sizeof url, "%s", (cdboi->ptr)+sizeof(long) );
380 client_write(HKEY("<oid_url>"));
381 xml_strout(url);
382 client_write(HKEY("</oid_url>\n"));
383 cprintf("<oid_usernum>%ld</oid_usernum>\n", usernum);
384 client_write(HKEY("</openid>\n"));
385 }
386 cdb_free(cdboi);
387 }
388}
389
390
392 struct cdbdata *cdbcfg;
393 int keylen = 0;
394 char *key = NULL;
395 char *value = NULL;
396
398 while (cdbcfg = cdb_next_item(CDB_CONFIG), cdbcfg != NULL) {
399
400 keylen = strlen(cdbcfg->ptr);
401 key = cdbcfg->ptr;
402 value = cdbcfg->ptr + keylen + 1;
403
404 client_write("<config key=\"", 13);
405 xml_strout(key);
406 client_write("\">", 2);
407 xml_strout(value);
408 client_write("</config>\n", 10);
409 cdb_free(cdbcfg);
410 }
411}
412
413
415 char buf[SIZ];
416 long msgnum;
417 int count = 0;
418 int progress = 0;
419 int prev_progress = 0;
420 CitContext *Ctx;
421
422 Ctx = CC;
424 if (migr_global_message_list != NULL) {
425 syslog(LOG_INFO, "migrate: opened %s", migr_tempfilename1);
426 while ((Ctx->kill_me == 0) &&
427 (fgets(buf, sizeof(buf), migr_global_message_list) != NULL)) {
428 msgnum = atol(buf);
429 if (msgnum > 0L) {
430 migr_export_message(msgnum);
431 ++count;
432 }
433 progress = (count * 74 / total_msgs) + 25 ;
434 if ((progress > prev_progress) && (progress < 100)) {
435 cprintf("<progress>%d</progress>\n", progress);
436 }
437 prev_progress = progress;
438 }
440 }
441 if (Ctx->kill_me == 0) {
442 syslog(LOG_INFO, "migrate: exported %d messages.", count);
443 }
444 else {
445 syslog(LOG_ERR, "migrate: export aborted due to client disconnect!");
446 }
447
448 migr_export_message(-1L); // This frees the encoding buffer
449}
450
451
452void migr_do_export(void) {
453 CitContext *Ctx;
454
455 Ctx = CC;
456 cprintf("%d Exporting all Citadel databases.\n", LISTING_FOLLOWS);
457 Ctx->dont_term = 1;
458
459 client_write(HKEY("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"));
460 client_write(HKEY("<citadel_migrate_data>\n"));
461 cprintf("<version>%d</version>\n", REV_LEVEL);
462 cprintf("<progress>%d</progress>\n", 0);
463
464 // export the configuration database
466 cprintf("<progress>%d</progress>\n", 2);
467
468 if (Ctx->kill_me == 0) migr_export_users();
469 cprintf("<progress>%d</progress>\n", 7);
470 if (Ctx->kill_me == 0) migr_export_openids();
471 cprintf("<progress>%d</progress>\n", 12);
472 if (Ctx->kill_me == 0) migr_export_rooms();
473 cprintf("<progress>%d</progress>\n", 17);
474 if (Ctx->kill_me == 0) migr_export_floors();
475 cprintf("<progress>%d</progress>\n", 18);
476 if (Ctx->kill_me == 0) migr_export_visits();
477 cprintf("<progress>%d</progress>\n", 25);
478 if (Ctx->kill_me == 0) migr_export_messages();
479 cprintf("<progress>%d</progress>\n", 100);
480 client_write(HKEY("</citadel_migrate_data>\n"));
481 client_write(HKEY("000\n"));
482 Ctx->dont_term = 0;
483}
484
485
486// Import code
487// Here's the code that implements the import side. It's going to end up
488// being one big loop with lots of global variables. I don't care.
489// You wouldn't run multiple concurrent imports anyway. If this offends your
490// delicate sensibilities then go rewrite it in Ruby on Rails or something.
491
492
493int citadel_migrate_data = 0; // Are we inside a <citadel_migrate_data> tag pair?
494StrBuf *migr_chardata = NULL;
495StrBuf *migr_MsgData = NULL;
498char openid_url[512];
502int floornum = 0;
506
507// This callback stores up the data which appears in between tags.
508void migr_xml_chardata(void *data, const XML_Char *s, int len) {
509 StrBufAppendBufPlain(migr_chardata, s, len, 0);
510}
511
512
513void migr_xml_start(void *data, const char *el, const char **attr) {
514 int i;
515
516 // *** GENERAL STUFF ***
517
518 // Reset chardata_len to zero and init buffer
519 FlushStrBuf(migr_chardata);
520 FlushStrBuf(migr_MsgData);
521
522 if (!strcasecmp(el, "citadel_migrate_data")) {
524
525 // As soon as it looks like the input data is a genuine Citadel XML export,
526 // whack the existing database on disk to make room for the new one.
527 if (citadel_migrate_data == 1) {
528 syslog(LOG_INFO, "migrate: erasing existing databases so we can receive the incoming import");
529 for (i = 0; i < MAXCDB; ++i) {
530 cdb_trunc(i);
531 }
532 }
533 return;
534 }
535
536 if (citadel_migrate_data != 1) {
537 syslog(LOG_ERR, "migrate: out-of-sequence tag <%s> detected. Warning: ODD-DATA!", el);
538 return;
539 }
540
541 // When we begin receiving XML for one of these record types, clear out the associated
542 // buffer so we don't accidentally carry over any data from a previous record.
543 if (!strcasecmp(el, "user")) memset(&usbuf, 0, sizeof (struct ctdluser));
544 else if (!strcasecmp(el, "openid")) memset(openid_url, 0, sizeof openid_url);
545 else if (!strcasecmp(el, "room")) memset(&qrbuf, 0, sizeof (struct ctdlroom));
546 else if (!strcasecmp(el, "room_messages")) memset(FRname, 0, sizeof FRname);
547 else if (!strcasecmp(el, "floor")) memset(&flbuf, 0, sizeof (struct floor));
548 else if (!strcasecmp(el, "visit")) memset(&vbuf, 0, sizeof (visit));
549
550 else if (!strcasecmp(el, "message")) {
551 memset(&smi, 0, sizeof (struct MetaData));
552 import_msgnum = 0;
553 }
554 else if (!strcasecmp(el, "config")) {
555 if (ikey != NULL) {
556 free(ikey);
557 ikey = NULL;
558 }
559 while (*attr) {
560 if (!strcasecmp(attr[0], "key")) {
561 ikey = strdup(attr[1]);
562 }
563 attr += 2;
564 }
565 }
566
567}
568
569
570int migr_userrecord(void *data, const char *el) {
571 if (!strcasecmp(el, "u_version")) usbuf.version = atoi(ChrPtr(migr_chardata));
572 else if (!strcasecmp(el, "u_uid")) usbuf.uid = atol(ChrPtr(migr_chardata));
573 else if (!strcasecmp(el, "u_password")) safestrncpy(usbuf.password, ChrPtr(migr_chardata), sizeof usbuf.password);
574 else if (!strcasecmp(el, "u_flags")) usbuf.flags = atoi(ChrPtr(migr_chardata));
575 else if (!strcasecmp(el, "u_timescalled")) usbuf.timescalled = atol(ChrPtr(migr_chardata));
576 else if (!strcasecmp(el, "u_posted")) usbuf.posted = atol(ChrPtr(migr_chardata));
577 else if (!strcasecmp(el, "u_axlevel")) usbuf.axlevel = atoi(ChrPtr(migr_chardata));
578 else if (!strcasecmp(el, "u_usernum")) usbuf.usernum = atol(ChrPtr(migr_chardata));
579 else if (!strcasecmp(el, "u_lastcall")) usbuf.lastcall = atol(ChrPtr(migr_chardata));
580 else if (!strcasecmp(el, "u_USuserpurge")) usbuf.USuserpurge = atoi(ChrPtr(migr_chardata));
581 else if (!strcasecmp(el, "u_fullname")) safestrncpy(usbuf.fullname, ChrPtr(migr_chardata), sizeof usbuf.fullname);
582 else if (!strcasecmp(el, "u_msgnum_bio")) usbuf.msgnum_bio = atol(ChrPtr(migr_chardata));
583 else if (!strcasecmp(el, "u_msgnum_pic")) usbuf.msgnum_pic = atol(ChrPtr(migr_chardata));
584 else if (!strcasecmp(el, "u_emailaddrs")) safestrncpy(usbuf.emailaddrs, ChrPtr(migr_chardata), sizeof usbuf.emailaddrs);
585 else if (!strcasecmp(el, "u_msgnum_inboxrules")) usbuf.msgnum_inboxrules = atol(ChrPtr(migr_chardata));
586 else if (!strcasecmp(el, "u_lastproc_inboxrules")) usbuf.lastproc_inboxrules = atol(ChrPtr(migr_chardata));
587 else return 0;
588 return 1;
589}
590
591
592int migr_roomrecord(void *data, const char *el) {
593 if (!strcasecmp(el, "QRname")) safestrncpy(qrbuf.QRname, ChrPtr(migr_chardata), sizeof qrbuf.QRname);
594 else if (!strcasecmp(el, "QRpasswd")) safestrncpy(qrbuf.QRpasswd, ChrPtr(migr_chardata), sizeof qrbuf.QRpasswd);
595 else if (!strcasecmp(el, "QRroomaide")) qrbuf.QRroomaide = atol(ChrPtr(migr_chardata));
596 else if (!strcasecmp(el, "QRhighest")) qrbuf.QRhighest = atol(ChrPtr(migr_chardata));
597 else if (!strcasecmp(el, "QRgen")) qrbuf.QRgen = atol(ChrPtr(migr_chardata));
598 else if (!strcasecmp(el, "QRflags")) qrbuf.QRflags = atoi(ChrPtr(migr_chardata));
599 else if (!strcasecmp(el, "QRdirname")) safestrncpy(qrbuf.QRdirname, ChrPtr(migr_chardata), sizeof qrbuf.QRdirname);
600 else if (!strcasecmp(el, "QRfloor")) qrbuf.QRfloor = atoi(ChrPtr(migr_chardata));
601 else if (!strcasecmp(el, "QRmtime")) qrbuf.QRmtime = atol(ChrPtr(migr_chardata));
602 else if (!strcasecmp(el, "QRexpire_mode")) qrbuf.QRep.expire_mode = atoi(ChrPtr(migr_chardata));
603 else if (!strcasecmp(el, "QRexpire_value")) qrbuf.QRep.expire_value = atoi(ChrPtr(migr_chardata));
604 else if (!strcasecmp(el, "QRnumber")) qrbuf.QRnumber = atol(ChrPtr(migr_chardata));
605 else if (!strcasecmp(el, "QRorder")) qrbuf.QRorder = atoi(ChrPtr(migr_chardata));
606 else if (!strcasecmp(el, "QRflags2")) qrbuf.QRflags2 = atoi(ChrPtr(migr_chardata));
607 else if (!strcasecmp(el, "QRdefaultview")) qrbuf.QRdefaultview = atoi(ChrPtr(migr_chardata));
608 else if (!strcasecmp(el, "msgnum_info")) qrbuf.msgnum_info = atol(ChrPtr(migr_chardata));
609 else if (!strcasecmp(el, "msgnum_pic")) qrbuf.msgnum_pic = atol(ChrPtr(migr_chardata));
610 else return 0;
611 return 1;
612}
613
614
615int migr_floorrecord(void *data, const char *el) {
616 if (!strcasecmp(el, "f_num")) floornum = atoi(ChrPtr(migr_chardata));
617 else if (!strcasecmp(el, "f_flags")) flbuf.f_flags = atoi(ChrPtr(migr_chardata));
618 else if (!strcasecmp(el, "f_name")) safestrncpy(flbuf.f_name, ChrPtr(migr_chardata), sizeof flbuf.f_name);
619 else if (!strcasecmp(el, "f_ref_count")) flbuf.f_ref_count = atoi(ChrPtr(migr_chardata));
620 else if (!strcasecmp(el, "f_ep_expire_mode")) flbuf.f_ep.expire_mode = atoi(ChrPtr(migr_chardata));
621 else if (!strcasecmp(el, "f_ep_expire_value")) flbuf.f_ep.expire_value = atoi(ChrPtr(migr_chardata));
622 else return 0;
623 return 1;
624}
625
626
627int migr_visitrecord(void *data, const char *el) {
628 if (!strcasecmp(el, "v_roomnum")) vbuf.v_roomnum = atol(ChrPtr(migr_chardata));
629 else if (!strcasecmp(el, "v_roomgen")) vbuf.v_roomgen = atol(ChrPtr(migr_chardata));
630 else if (!strcasecmp(el, "v_usernum")) vbuf.v_usernum = atol(ChrPtr(migr_chardata));
631
632 else if (!strcasecmp(el, "v_seen")) {
633 int is_textual_seen = 0;
634 int i;
635 int max = StrLength(migr_chardata);
636
637 vbuf.v_lastseen = atol(ChrPtr(migr_chardata));
638 is_textual_seen = 0;
639 for (i=0; i < max; ++i)
640 if (!isdigit(ChrPtr(migr_chardata)[i]))
641 is_textual_seen = 1;
642 if (is_textual_seen)
643 safestrncpy(vbuf.v_seen, ChrPtr(migr_chardata), sizeof vbuf.v_seen);
644 }
645
646 else if (!strcasecmp(el, "v_answered")) safestrncpy(vbuf.v_answered, ChrPtr(migr_chardata), sizeof vbuf.v_answered);
647 else if (!strcasecmp(el, "v_flags")) vbuf.v_flags = atoi(ChrPtr(migr_chardata));
648 else if (!strcasecmp(el, "v_view")) vbuf.v_view = atoi(ChrPtr(migr_chardata));
649 else return 0;
650 return 1;
651}
652
653
654void migr_xml_end(void *data, const char *el) {
655 const char *ptr;
656 int msgcount = 0;
657 long msgnum = 0L;
658 long *msglist = NULL;
659 int msglist_alloc = 0;
660 // *** GENERAL STUFF ***
661
662 if (!strcasecmp(el, "citadel_migrate_data")) {
664 return;
665 }
666
667 if (citadel_migrate_data != 1) {
668 syslog(LOG_ERR, "migrate: out-of-sequence tag <%s> detected. Warning: ODD-DATA!", el);
669 return;
670 }
671
672 // syslog(LOG_DEBUG, "END TAG: <%s> DATA: <%s>\n", el, (migr_chardata_len ? migr_chardata : ""));
673
674 // *** CONFIG ***
675
676 if (!strcasecmp(el, "config")) {
677 syslog(LOG_DEBUG, "migrate: imported config key=%s", ikey);
678
679 if (ikey != NULL) {
680 CtdlSetConfigStr(ikey, (char *)ChrPtr(migr_chardata));
681 free(ikey);
682 ikey = NULL;
683 }
684 else {
685 syslog(LOG_INFO, "migrate: closed a <config> tag but no key name was supplied.");
686 }
687 }
688
689 // *** USER ***
690 else if ((!strncasecmp(el, HKEY("u_"))) &&
691 migr_userrecord(data, el))
692 ; /* Nothing to do anymore */
693 else if (!strcasecmp(el, "user")) {
695 syslog(LOG_INFO, "migrate: imported user: %s", usbuf.fullname);
696 }
697
698 // *** OPENID ***
699
700 else if (!strcasecmp(el, "oid_url")) safestrncpy(openid_url, ChrPtr(migr_chardata), sizeof openid_url);
701 else if (!strcasecmp(el, "oid_usernum")) openid_usernum = atol(ChrPtr(migr_chardata));
702
703 else if (!strcasecmp(el, "openid")) { // see serv_openid_rp.c for a description of the record format
704 char *oid_data;
705 int oid_data_len;
706 oid_data_len = sizeof(long) + strlen(openid_url) + 1;
707 oid_data = malloc(oid_data_len);
708 memcpy(oid_data, &openid_usernum, sizeof(long));
709 memcpy(&oid_data[sizeof(long)], openid_url, strlen(openid_url) + 1);
710 cdb_store(CDB_EXTAUTH, openid_url, strlen(openid_url), oid_data, oid_data_len);
711 free(oid_data);
712 syslog(LOG_INFO, "migrate: imported OpenID: %s (%ld)", openid_url, openid_usernum);
713 }
714
715 // *** ROOM ***
716 else if ((!strncasecmp(el, HKEY("QR"))) &&
717 migr_roomrecord(data, el))
718 ; // Nothing to do anymore
719 else if (!strcasecmp(el, "room")) {
721 syslog(LOG_INFO, "migrate: imported room: %s", qrbuf.QRname);
722 }
723
724 // *** ROOM MESSAGE POINTERS ***
725
726 else if (!strcasecmp(el, "FRname")) {
727 safestrncpy(FRname, ChrPtr(migr_chardata), sizeof FRname);
728 }
729
730 else if (!strcasecmp(el, "FRmsglist")) {
731 if (!IsEmptyStr(FRname)) {
732 msgcount = 0;
733 msglist_alloc = 1000;
734 msglist = malloc(sizeof(long) * msglist_alloc);
735
736 syslog(LOG_DEBUG, "migrate: message list for: %s", FRname);
737
738 ptr = ChrPtr(migr_chardata);
739 while (*ptr != 0) {
740 while ((*ptr != 0) && (!isdigit(*ptr))) {
741 ++ptr;
742 }
743 if ((*ptr != 0) && (isdigit(*ptr))) {
744 msgnum = atol(ptr);
745 if (msgnum > 0L) {
746 if (msgcount >= msglist_alloc) {
747 msglist_alloc *= 2;
748 msglist = realloc(msglist, sizeof(long) * msglist_alloc);
749 }
750 msglist[msgcount++] = msgnum;
751 }
752 }
753 while ((*ptr != 0) && (isdigit(*ptr))) {
754 ++ptr;
755 }
756 }
757 }
758 if (msgcount > 0) {
759 CtdlSaveMsgPointersInRoom(FRname, msglist, msgcount, 0, NULL, 1);
760 }
761 free(msglist);
762 msglist = NULL;
763 msglist_alloc = 0;
764 syslog(LOG_DEBUG, "migrate: imported %d messages.", msgcount);
766 return;
767 }
768 }
769
770 // *** FLOORS ***
771 else if ((!strncasecmp(el, HKEY("f_"))) &&
772 migr_floorrecord(data, el))
773 ; // Nothing to do anymore
774
775 else if (!strcasecmp(el, "floor")) {
777 syslog(LOG_INFO, "migrate: imported floor #%d (%s)", floornum, flbuf.f_name);
778 }
779
780 // *** VISITS ***
781 else if ((!strncasecmp(el, HKEY("v_"))) && migr_visitrecord(data, el)) {
782 ; // Nothing to do anymore
783 }
784 else if (!strcasecmp(el, "visit")) {
785 put_visit(&vbuf);
786 syslog(LOG_INFO, "migrate: imported visit: %ld/%ld/%ld", vbuf.v_roomnum, vbuf.v_roomgen, vbuf.v_usernum);
787 }
788
789 // *** MESSAGES ***
790
791 else if (!strcasecmp(el, "msg_msgnum")) smi.meta_msgnum = import_msgnum = atol(ChrPtr(migr_chardata));
792 else if (!strcasecmp(el, "msg_meta_refcount")) smi.meta_refcount = atoi(ChrPtr(migr_chardata));
793 else if (!strcasecmp(el, "msg_meta_rfc822_length")) smi.meta_rfc822_length = atoi(ChrPtr(migr_chardata));
794 else if (!strcasecmp(el, "msg_meta_content_type")) safestrncpy(smi.meta_content_type, ChrPtr(migr_chardata), sizeof smi.meta_content_type);
795
796 else if (!strcasecmp(el, "msg_text")) {
797 long rc;
798 struct CtdlMessage *msg;
799
800 FlushStrBuf(migr_MsgData);
801 StrBufDecodeBase64To(migr_chardata, migr_MsgData);
802
804 ChrPtr(migr_MsgData),
805 StrLength(migr_MsgData));
806 if (msg != NULL) {
808 if (rc == 0) {
810 }
811 CM_Free(msg);
812 }
813 else {
814 rc = -1;
815 }
816
817 syslog(LOG_INFO,
818 "migrate: %s message #%ld, size=%d, ref=%d, body=%ld, content-type: %s",
819 (rc!= 0)?"failed to import":"imported",
821 StrLength(migr_MsgData),
825 );
826 memset(&smi, 0, sizeof(smi));
827 }
828
829 // *** MORE GENERAL STUFF ***
830
831 FlushStrBuf(migr_chardata);
832}
833
834
835// Import begins here
836void migr_do_import(void) {
837 XML_Parser xp;
838 char buf[SIZ];
839
841 migr_chardata = NewStrBufPlain(NULL, SIZ * 20);
842 migr_MsgData = NewStrBufPlain(NULL, SIZ * 20);
843 xp = XML_ParserCreate(NULL);
844 if (!xp) {
845 cprintf("%d Failed to create XML parser instance\n", ERROR+INTERNAL_ERROR);
846 return;
847 }
848 XML_SetElementHandler(xp, migr_xml_start, migr_xml_end);
849 XML_SetCharacterDataHandler(xp, migr_xml_chardata);
850
851 CC->dont_term = 1;
852
853 cprintf("%d sock it to me\n", SEND_LISTING);
855
857
858 while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) {
859 XML_Parse(xp, buf, strlen(buf), 0);
861 break; // Should we break or return?
862 }
863
864 XML_Parse(xp, "", 0, 1);
865 XML_ParserFree(xp);
866 FreeStrBuf(&migr_chardata);
867 FreeStrBuf(&migr_MsgData);
870 CtdlSetConfigInt("MM_fulltext_wordbreaker", -1); // Set an invalid wordbreaker to force re-indexing
871 CC->dont_term = 0;
872}
873
874
875// ******************************************************************************
876// * Dispatcher, Common code *
877// ******************************************************************************
878
879// Dump out the pathnames of directories which can be copied "as is"
881 cprintf("%d Don't forget these:\n", LISTING_FOLLOWS);
882 cprintf("files|%s\n", ctdl_file_dir);
883 cprintf("messages|%s\n", ctdl_message_dir);
884 cprintf("keys|%s\n", ctdl_key_dir);
885 cprintf("000\n");
886}
887
888
889// ******************************************************************************
890// * Repair database integrity *
891// ******************************************************************************
892
893StrBuf *PlainMessageBuf = NULL;
894HashList *UsedMessageIDS = NULL;
895
896int migr_restore_message_metadata(long msgnum, int refcount) {
897 struct MetaData smi;
898 struct CtdlMessage *msg;
899 char *mptr = NULL;
900
901 // We can use a static buffer here because there will never be more than
902 // one of this operation happening at any given time, and it's really best
903 // to just keep it allocated once instead of torturing malloc/free.
904 // Call this function with msgnum "-1" to free the buffer when finished.
905 static int encoded_alloc = 0;
906 static char *encoded_msg = NULL;
907
908 if (msgnum < 0) {
909 if ((encoded_alloc == 0) && (encoded_msg != NULL)) {
910 free(encoded_msg);
911 encoded_alloc = 0;
912 encoded_msg = NULL;
913 // todo FreeStrBuf(&PlainMessageBuf); PlainMessageBuf = NULL;
914 }
915 return 0;
916 }
917
918 if (PlainMessageBuf == NULL) {
919 PlainMessageBuf = NewStrBufPlain(NULL, 10*SIZ);
920 }
921
922 // Ok, here we go ...
923
924 msg = CtdlFetchMessage(msgnum, 1);
925 if (msg == NULL) {
926 return 1;
927 }
928
929 GetMetaData(&smi, msgnum);
930 smi.meta_msgnum = msgnum;
931 smi.meta_refcount = refcount;
932
933 // restore the content type from the message body:
934 mptr = bmstrcasestr(msg->cm_fields[eMesageText], "Content-type:");
935 if (mptr != NULL) {
936 char *aptr;
937 safestrncpy(smi.meta_content_type, &mptr[13], sizeof smi.meta_content_type);
938 striplt(smi.meta_content_type);
939 aptr = smi.meta_content_type;
940 while (!IsEmptyStr(aptr)) {
941 if ((*aptr == ';')
942 || (*aptr == ' ')
943 || (*aptr == 13)
944 || (*aptr == 10)) {
945 memset(aptr, 0, sizeof(smi.meta_content_type) - (aptr - smi.meta_content_type));
946 }
947 else aptr++;
948 }
949 }
950
951 CC->redirect_buffer = PlainMessageBuf;
953 smi.meta_rfc822_length = StrLength(CC->redirect_buffer);
954 CC->redirect_buffer = NULL;
955
956 syslog(LOG_INFO,
957 "migrate: setting message #%ld meta data to: refcount=%d, bodylength=%ld, content-type: %s",
962 );
963
965 CM_Free(msg);
966 return 0;
967}
968
969
970void migr_check_room_msg(long msgnum, void *userdata) {
971 fprintf(migr_global_message_list, "%ld %s\n", msgnum, CC->room.QRname);
972}
973
974
975void migr_check_rooms_backend(struct ctdlroom *buf, void *data) {
976 // message list goes inside this tag
977 CtdlGetRoom(&CC->room, buf->QRname);
978 CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, migr_check_room_msg, NULL);
979}
980
981
982void RemoveMessagesFromRooms(StrBuf *RoomNameVec, long msgnum) {
983 struct MetaData smi;
984 const char *Pos = NULL;
985 StrBuf *oneRoom = NewStrBuf();
986
987 syslog(LOG_INFO, "migrate: removing message pointer %ld from these rooms: %s", msgnum, ChrPtr(RoomNameVec));
988
989 while (Pos != StrBufNOTNULL){
990 StrBufExtract_NextToken(oneRoom, RoomNameVec, &Pos, '|');
991 CtdlDeleteMessages(ChrPtr(oneRoom), &msgnum, 1, "");
992 };
993 GetMetaData(&smi, msgnum);
994 AdjRefCount(msgnum, -smi.meta_refcount);
995}
996
997
999 char buf[SIZ];
1000 int failGetMessage;
1001 long msgnum = 0;
1002 int lastnum = 0;
1003 int refcount = 0;
1004 CitContext *Ctx;
1005 char *prn;
1006 StrBuf *RoomNames;
1007 char cmd[SIZ];
1008
1010 if (migr_global_message_list != NULL) {
1013 }
1014
1015 // Process the 'global' message list. (Sort it and remove dups.
1016 // Dups are ok because a message may be in more than one room, but
1017 // this will be handled by exporting the reference count, not by
1018 // exporting the message multiple times.)
1019 snprintf(cmd, sizeof cmd, "sort -n <%s >%s", migr_tempfilename1, migr_tempfilename2);
1020 if (system(cmd) != 0) {
1021 syslog(LOG_ERR, "migrate: error %d", errno);
1022 }
1023
1024 RoomNames = NewStrBuf();
1025 Ctx = CC;
1027 if (migr_global_message_list != NULL) {
1028 syslog(LOG_INFO, "migrate: opened %s", migr_tempfilename1);
1029 while ((Ctx->kill_me == 0) &&
1030 (fgets(buf, sizeof(buf), migr_global_message_list) != NULL)) {
1031 msgnum = atol(buf);
1032 if (msgnum == 0L)
1033 continue;
1034 if (lastnum == 0) {
1035 lastnum = msgnum;
1036 }
1037 prn = strchr(buf, ' ');
1038 if (lastnum != msgnum) {
1039 failGetMessage = migr_restore_message_metadata(lastnum, refcount);
1040 if (failGetMessage) {
1041 RemoveMessagesFromRooms(RoomNames, lastnum);
1042 }
1043 refcount = 1;
1044 lastnum = msgnum;
1045 if (prn != NULL) {
1046 StrBufPlain(RoomNames, prn + 1, -1);
1047 }
1048 StrBufTrim(RoomNames);
1049 }
1050 else {
1051 if (prn != NULL) {
1052 if (StrLength(RoomNames) > 0) {
1053 StrBufAppendBufPlain(RoomNames, HKEY("|"), 0);
1054 }
1055 StrBufAppendBufPlain(RoomNames, prn, -1, 1);
1056 StrBufTrim(RoomNames);
1057 }
1058 refcount ++;
1059 }
1060 lastnum = msgnum;
1061 }
1062 failGetMessage = migr_restore_message_metadata(msgnum, refcount);
1063 if (failGetMessage) {
1064 RemoveMessagesFromRooms(RoomNames, lastnum);
1065 }
1067 }
1068
1069 migr_restore_message_metadata(-1L, -1); // This frees the encoding buffer
1070 cprintf("%d system analysis completed", CIT_OK);
1071 Ctx->kill_me = 1;
1072}
1073
1074
1075// ******************************************************************************
1076// * Dispatcher, Common code *
1077// ******************************************************************************
1078void cmd_migr(char *cmdbuf) {
1079 char cmd[32];
1080
1081 if (CtdlAccessCheck(ac_aide)) return;
1082
1083 if (CtdlTrySingleUser()) {
1085 CtdlMakeTempFileName(migr_tempfilename1, sizeof migr_tempfilename1);
1086 CtdlMakeTempFileName(migr_tempfilename2, sizeof migr_tempfilename2);
1087
1088 extract_token(cmd, cmdbuf, 0, '|', sizeof cmd);
1089 if (!strcasecmp(cmd, "export")) {
1091 }
1092 else if (!strcasecmp(cmd, "import")) {
1094 }
1095 else if (!strcasecmp(cmd, "listdirs")) {
1097 }
1098 else if (!strcasecmp(cmd, "restoremeta")) {
1100 }
1101 else {
1102 cprintf("%d illegal command\n", ERROR + ILLEGAL_VALUE);
1103 }
1104
1105 unlink(migr_tempfilename1);
1106 unlink(migr_tempfilename2);
1107
1110 }
1111 else {
1112 cprintf("%d The migrator is already running.\n", ERROR + RESOURCE_BUSY);
1113 }
1114}
1115
1116
1117// ******************************************************************************
1118// * Module Hook *
1119// ******************************************************************************
1120
1122{
1123 if (!threading)
1124 {
1125 CtdlRegisterProtoHook(cmd_migr, "MIGR", "Across-the-wire migration");
1126 }
1127
1128 // return our module name for the log
1129 return "migrate";
1130}
#define ROOMNAMELEN
Definition: citadel.h:56
#define REV_LEVEL
Definition: citadel.h:35
#define ctdl_message_dir
Definition: citadel_dirs.h:14
#define ctdl_file_dir
Definition: citadel_dirs.h:9
#define ctdl_key_dir
Definition: citadel_dirs.h:13
void CtdlSetConfigStr(char *key, char *value)
Definition: config.c:326
void CtdlSetConfigInt(char *key, int value)
Definition: config.c:359
int CtdlTrySingleUser(void)
Definition: context.c:32
void CtdlEndSingleUser(void)
Definition: context.c:49
#define CC
Definition: context.h:140
int CtdlAccessCheck(int)
Definition: user_ops.c:389
void CtdlPutUser(struct ctdluser *usbuf)
Definition: user_ops.c:128
void CtdlGetFloor(struct floor *flbuf, int floor_num)
Definition: room_ops.c:503
int CtdlGetRoom(struct ctdlroom *qrbuf, const char *room_name)
Definition: room_ops.c:342
void CtdlDisableHouseKeeping(void)
Definition: housekeeping.c:169
void CtdlEnableHouseKeeping(void)
Definition: housekeeping.c:188
void CtdlPutRoom(struct ctdlroom *)
Definition: room_ops.c:428
void CtdlForEachRoom(ForEachRoomCallBack CB, void *in_data)
Definition: room_ops.c:606
void CtdlPutFloor(struct floor *flbuf, int floor_num)
Definition: room_ops.c:571
@ ac_aide
Definition: ctdl_module.h:246
int CtdlGetUser(struct ctdluser *usbuf, char *name)
Definition: user_ops.c:77
void CtdlRegisterProtoHook(void(*handler)(char *), char *cmd, char *desc)
#define CTDL_MODULE_INIT(module_name)
Definition: ctdl_module.h:50
void cdb_free(struct cdbdata *cdb)
Definition: database.c:609
struct cdbdata * cdb_next_item(int cdb)
Definition: database.c:655
int cdb_store(int cdb, const void *ckey, int ckeylen, void *cdata, int cdatalen)
Definition: database.c:397
void cdb_trunc(int cdb)
Definition: database.c:726
void cdb_rewind(int cdb)
Definition: database.c:631
void rebuild_euid_index(void)
Definition: euidindex.c:182
#define CIT_OK
Definition: ipcdef.h:6
#define ILLEGAL_VALUE
Definition: ipcdef.h:16
#define INTERNAL_ERROR
Definition: ipcdef.h:14
#define LISTING_FOLLOWS
Definition: ipcdef.h:5
#define RESOURCE_BUSY
Definition: ipcdef.h:25
#define QR_DIRECTORY
Definition: ipcdef.h:44
#define ERROR
Definition: ipcdef.h:9
#define SEND_LISTING
Definition: ipcdef.h:8
void CM_Free(struct CtdlMessage *msg)
Definition: msgbase.c:310
void AdjRefCount(long msgnum, int incr)
Definition: msgbase.c:3441
long CtdlSaveThisMessage(struct CtdlMessage *msg, long msgid, int Reply)
Definition: msgbase.c:2414
struct CtdlMessage * CtdlDeserializeMessage(long msgnum, int with_body, const char *Buffer, long Length)
Definition: msgbase.c:1068
void GetMetaData(struct MetaData *smibuf, long msgnum)
Definition: msgbase.c:3383
void CtdlSerializeMessage(struct ser_ret *ret, struct CtdlMessage *msg)
Definition: msgbase.c:2520
int CtdlForEachMessage(int mode, long ref, char *search_string, char *content_type, struct CtdlMessage *compare, ForEachMsgCallback CallBack, void *userdata)
Definition: msgbase.c:626
int CtdlOutputPreLoadedMsg(struct CtdlMessage *TheMessage, int mode, int headers_only, int do_proto, int crlf, int flags)
Definition: msgbase.c:1969
struct CtdlMessage * CtdlFetchMessage(long msgnum, int with_body)
Definition: msgbase.c:1135
int CtdlDeleteMessages(const char *room_name, long *dmsgnums, int num_dmsgnums, char *content_type)
Definition: msgbase.c:3240
void PutMetaData(struct MetaData *smibuf)
Definition: msgbase.c:3411
int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newmsgs, int do_repl_check, struct CtdlMessage *supplied_msg, int suppress_refcount_adj)
Definition: msgbase.c:2236
#define HEADERS_ALL
Definition: msgbase.h:39
#define QP_EADDR
Definition: msgbase.h:160
@ MSGS_ALL
Definition: msgbase.h:6
void * malloc(size_t)
void free(void *)
void migr_do_restore_meta(void)
Definition: serv_migrate.c:998
void migr_export_configs(void)
Definition: serv_migrate.c:391
struct floor flbuf
Definition: serv_migrate.c:501
void migr_do_listdirs(void)
Definition: serv_migrate.c:880
char * ikey
Definition: serv_migrate.c:58
int floornum
Definition: serv_migrate.c:502
FILE * migr_global_message_list
Definition: serv_migrate.c:56
struct MetaData smi
Definition: serv_migrate.c:504
int migr_userrecord(void *data, const char *el)
Definition: serv_migrate.c:570
int migr_floorrecord(void *data, const char *el)
Definition: serv_migrate.c:615
void migr_export_openids(void)
Definition: serv_migrate.c:369
char migr_tempfilename2[PATH_MAX]
Definition: serv_migrate.c:55
int citadel_migrate_data
Definition: serv_migrate.c:493
void migr_export_rooms_backend(struct ctdlroom *buf, void *data)
Definition: serv_migrate.c:142
long import_msgnum
Definition: serv_migrate.c:505
void migr_export_users(void)
Definition: serv_migrate.c:126
void migr_export_floors(void)
Definition: serv_migrate.c:219
struct ctdlroom qrbuf
Definition: serv_migrate.c:497
char FRname[128]
Definition: serv_migrate.c:500
void migr_export_visits(void)
Definition: serv_migrate.c:254
void migr_export_room_msg(long msgnum, void *userdata)
Definition: serv_migrate.c:131
int migr_restore_message_metadata(long msgnum, int refcount)
Definition: serv_migrate.c:896
void migr_export_users_backend(char *username, void *data)
Definition: serv_migrate.c:98
int is_sequence_set(char *s)
Definition: serv_migrate.c:239
StrBuf * migr_MsgData
Definition: serv_migrate.c:495
void migr_do_import(void)
Definition: serv_migrate.c:836
void migr_xml_chardata(void *data, const XML_Char *s, int len)
Definition: serv_migrate.c:508
visit vbuf
Definition: serv_migrate.c:503
int migr_roomrecord(void *data, const char *el)
Definition: serv_migrate.c:592
void xml_strout(char *str)
Definition: serv_migrate.c:65
struct ctdluser usbuf
Definition: serv_migrate.c:496
void migr_export_rooms(void)
Definition: serv_migrate.c:184
void cmd_migr(char *cmdbuf)
void migr_do_export(void)
Definition: serv_migrate.c:452
long openid_usernum
Definition: serv_migrate.c:499
void migr_check_room_msg(long msgnum, void *userdata)
Definition: serv_migrate.c:970
char migr_tempfilename1[PATH_MAX]
Definition: serv_migrate.c:54
void migr_export_messages(void)
Definition: serv_migrate.c:414
void migr_xml_start(void *data, const char *el, const char **attr)
Definition: serv_migrate.c:513
char openid_url[512]
Definition: serv_migrate.c:498
int migr_visitrecord(void *data, const char *el)
Definition: serv_migrate.c:627
StrBuf * migr_chardata
Definition: serv_migrate.c:494
void migr_xml_end(void *data, const char *el)
Definition: serv_migrate.c:654
void migr_check_rooms_backend(struct ctdlroom *buf, void *data)
Definition: serv_migrate.c:975
int total_msgs
Definition: serv_migrate.c:57
StrBuf * PlainMessageBuf
Definition: serv_migrate.c:893
void migr_export_message(long msgnum)
Definition: serv_migrate.c:294
void RemoveMessagesFromRooms(StrBuf *RoomNameVec, long msgnum)
Definition: serv_migrate.c:982
HashList * UsedMessageIDS
Definition: serv_migrate.c:894
@ eMesageText
Definition: server.h:315
@ MT_RFC822
Definition: server.h:167
@ CDB_VISIT
Definition: server.h:190
@ MAXCDB
Definition: server.h:199
@ CDB_EXTAUTH
Definition: server.h:197
@ CDB_CONFIG
Definition: server.h:198
void progress(char *text, long int curr, long int cmax)
Definition: setup.c:291
int snprintf(char *buf, size_t max, const char *fmt,...)
Definition: snprintf.c:69
int kill_me
Definition: context.h:50
int dont_term
Definition: context.h:45
char * cm_fields[256]
Definition: server.h:37
int expire_mode
Definition: citadel.h:65
int expire_value
Definition: citadel.h:66
char meta_content_type[64]
Definition: server.h:270
long meta_rfc822_length
Definition: server.h:271
int meta_refcount
Definition: server.h:269
long meta_msgnum
Definition: server.h:268
long v_lastseen
Definition: server.h:249
long v_roomgen
Definition: server.h:247
long v_roomnum
Definition: server.h:246
char v_answered[4096]
Definition: server.h:252
long v_usernum
Definition: server.h:248
unsigned int v_flags
Definition: server.h:250
char v_seen[4096]
Definition: server.h:251
int v_view
Definition: server.h:253
size_t len
Definition: server.h:203
char * ptr
Definition: server.h:204
char QRfloor
Definition: citadel.h:116
unsigned QRflags2
Definition: citadel.h:121
time_t QRmtime
Definition: citadel.h:117
long QRroomaide
Definition: citadel.h:110
long msgnum_info
Definition: citadel.h:115
char QRname[128]
Definition: citadel.h:108
char QRpasswd[10]
Definition: citadel.h:109
long QRnumber
Definition: citadel.h:119
struct ExpirePolicy QRep
Definition: citadel.h:118
unsigned QRflags
Definition: citadel.h:113
long QRhighest
Definition: citadel.h:111
time_t QRgen
Definition: citadel.h:112
long msgnum_pic
Definition: citadel.h:123
char QRdirname[15]
Definition: citadel.h:114
int QRdefaultview
Definition: citadel.h:122
char QRorder
Definition: citadel.h:120
long posted
Definition: citadel.h:85
long msgnum_bio
Definition: citadel.h:91
unsigned flags
Definition: citadel.h:83
cit_uint8_t axlevel
Definition: citadel.h:86
char fullname[64]
Definition: citadel.h:90
time_t lastcall
Definition: citadel.h:88
long msgnum_inboxrules
Definition: citadel.h:94
long timescalled
Definition: citadel.h:84
uid_t uid
Definition: citadel.h:81
long usernum
Definition: citadel.h:87
int version
Definition: citadel.h:80
char password[32]
Definition: citadel.h:82
int USuserpurge
Definition: citadel.h:89
long msgnum_pic
Definition: citadel.h:92
long lastproc_inboxrules
Definition: citadel.h:95
char emailaddrs[512]
Definition: citadel.h:93
Definition: citadel.h:145
struct ExpirePolicy f_ep
Definition: citadel.h:149
int f_ref_count
Definition: citadel.h:148
char f_name[256]
Definition: citadel.h:147
unsigned short f_flags
Definition: citadel.h:146
size_t len
Definition: server.h:289
unsigned char * ser
Definition: server.h:290
#define SIZ
Definition: sysconfig.h:33
#define MAXFLOORS
Definition: sysconfig.h:25
void cprintf(const char *format,...)
Definition: sysdep.c:381
int client_getln(char *buf, int bufsize)
Definition: sysdep.c:548
int client_write(const char *buf, int nbytes)
Definition: sysdep.c:307
void client_set_inbound_buf(long N)
Definition: sysdep.c:440
void unbuffer_output(void)
Definition: sysdep.c:276
int server_shutting_down
Definition: threads.c:31
void ForEachUser(void(*CallBack)(char *, void *out_data), void *in_data)
Definition: user_ops.c:1206
void rebuild_usersbynumber(void)
Definition: user_ops.c:496
void put_visit(visit *newvisit)
Definition: user_ops.c:287