Removed serv_migrate.c and ctdlmigrate. They are replaced by ctdldump and ctdlload.
authorArt Cancro <ajc@citadel.org>
Tue, 18 Jul 2023 03:42:29 +0000 (18:42 -0900)
committerArt Cancro <ajc@citadel.org>
Tue, 18 Jul 2023 03:42:29 +0000 (18:42 -0900)
citadel/Makefile
citadel/server/modules/migrate/serv_migrate.c [deleted file]
citadel/server/modules_init.c
citadel/utils/ctdlmigrate.c [deleted file]

index edd3d0282ee69a0d54a714cc4beb283549b2b1d6..87c3101585a7a0b889b2eb3cb090725f6849301d 100644 (file)
@@ -10,7 +10,7 @@
 # config.mk is generated by ./configure
 include config.mk
 
-all := citserver setup ctdlmigrate sendcommand citmail chkpw chkpwd ctdldump ctdlload
+all := citserver setup sendcommand citmail chkpw chkpwd ctdldump ctdlload
 all: $(all)
 
 SRCDIRS := $(wildcard server server/modules/*)
diff --git a/citadel/server/modules/migrate/serv_migrate.c b/citadel/server/modules/migrate/serv_migrate.c
deleted file mode 100644 (file)
index 3a58bac..0000000
+++ /dev/null
@@ -1,1080 +0,0 @@
-// This module dumps and/or loads the Citadel database in XML format.
-//
-// Copyright (c) 1987-2023 by the citadel.org team
-//
-// This program is open source software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 3.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// Explanation of <progress> tags:
-//
-// 0%          started
-// 2%          finished exporting configuration
-// 7%          finished exporting users
-// 12%
-// 17%         finished exporting rooms
-// 18%         finished exporting floors
-// 25%         finished exporting visits
-// 26-99%      exporting messages
-// 100%                finished exporting messages
-//
-// These tags are inserted into the XML stream to give the reader an approximation of its progress.
-
-#include "../../sysdep.h"
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <pwd.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <time.h>
-#include <sys/wait.h>
-#include <string.h>
-#include <ctype.h>
-#include <limits.h>
-#include <expat.h>
-#include <libcitadel.h>
-#include "../../citadel_defs.h"
-#include "../../server.h"
-#include "../../citserver.h"
-#include "../../support.h"
-#include "../../config.h"
-#include "../../database.h"
-#include "../../msgbase.h"
-#include "../../user_ops.h"
-#include "../../euidindex.h"
-#include "../../internet_addressing.h"
-#include "../../ctdl_module.h"
-
-char migr_tempfilename1[PATH_MAX];
-char migr_tempfilename2[PATH_MAX];
-FILE *migr_global_message_list;
-int total_msgs = 0;
-char *ikey = NULL;                     // If we're importing a config key we store it here.
-
-//*****************************************************************************
-//*       Code which implements the export appears in this section            *
-//*****************************************************************************
-
-// Output a string to the client with these characters escaped:  & < > " '
-void xml_strout(char *str) {
-
-       char *c = str;
-
-       if (str == NULL) {
-               return;
-       }
-
-       while (*c != 0) {
-               if (*c == '\"') {
-                       client_write(HKEY("&quot;"));
-               }
-               else if (*c == '\'') {
-                       client_write(HKEY("&apos;"));
-               }
-               else if (*c == '<') {
-                       client_write(HKEY("&lt;"));
-               }
-               else if (*c == '>') {
-                       client_write(HKEY("&gt;"));
-               }
-               else if (*c == '&') {
-                       client_write(HKEY("&amp;"));
-               }
-               else {
-                       client_write(c, 1);
-               }
-               ++c;
-       }
-}
-
-
-// Export a user record as XML
-void migr_export_users_backend(char *username, void *data) {
-
-       struct ctdluser u;
-       if (CtdlGetUser(&u, username) != 0) {
-               return;
-       }
-
-       client_write(HKEY("<user>\n"));
-       cprintf("<u_version>%d</u_version>\n", u.version);
-       cprintf("<u_uid>%ld</u_uid>\n", (long)u.uid);
-       client_write(HKEY("<u_password>"));     xml_strout(u.password);         client_write(HKEY("</u_password>\n"));
-       cprintf("<u_flags>%u</u_flags>\n", u.flags);
-       cprintf("<u_axlevel>%d</u_axlevel>\n", u.axlevel);
-       cprintf("<u_usernum>%ld</u_usernum>\n", u.usernum);
-       cprintf("<u_lastcall>%ld</u_lastcall>\n", (long)u.lastcall);
-       cprintf("<u_USuserpurge>%d</u_USuserpurge>\n", u.USuserpurge);
-       client_write(HKEY("<u_fullname>"));     xml_strout(u.fullname);         client_write(HKEY("</u_fullname>\n"));
-       cprintf("<u_msgnum_bio>%ld</u_msgnum_bio>\n", u.msgnum_bio);
-       cprintf("<u_msgnum_pic>%ld</u_msgnum_pic>\n", u.msgnum_pic);
-       cprintf("<u_emailaddrs>%s</u_emailaddrs>\n", u.emailaddrs);
-       cprintf("<u_msgnum_inboxrules>%ld</u_msgnum_inboxrules>\n", u.msgnum_inboxrules);
-       cprintf("<u_lastproc_inboxrules>%ld</u_lastproc_inboxrules>\n", u.lastproc_inboxrules);
-       client_write(HKEY("</user>\n"));
-}
-
-
-void migr_export_users(void) {
-       ForEachUser(migr_export_users_backend, NULL);
-}
-
-
-void migr_export_room_msg(long msgnum, void *userdata) {
-       static int count = 0;
-
-       cprintf("%ld,", msgnum);
-       if (++count%10==0) {
-               cprintf("\n");
-       }
-       fprintf(migr_global_message_list, "%ld\n", msgnum);
-}
-
-
-void migr_export_rooms_backend(struct ctdlroom *buf, void *data) {
-       client_write(HKEY("<room>\n"));
-       client_write(HKEY("<QRname>"));
-       xml_strout(buf->QRname);
-       client_write(HKEY("</QRname>\n"));
-       client_write(HKEY("<QRpasswd>"));
-       xml_strout(buf->QRpasswd);
-       client_write(HKEY("</QRpasswd>\n"));
-       cprintf("<QRroomaide>%ld</QRroomaide>\n", buf->QRroomaide);
-       cprintf("<QRhighest>%ld</QRhighest>\n", buf->QRhighest);
-       cprintf("<QRgen>%ld</QRgen>\n", (long)buf->QRgen);
-       cprintf("<QRflags>%u</QRflags>\n", buf->QRflags);
-       if (buf->QRflags & QR_DIRECTORY) {
-               client_write(HKEY("<QRdirname>"));
-               xml_strout(buf->QRdirname);
-               client_write(HKEY("</QRdirname>\n"));
-       }
-       cprintf("<QRfloor>%d</QRfloor>\n", buf->QRfloor);
-       cprintf("<QRmtime>%ld</QRmtime>\n", (long)buf->QRmtime);
-       cprintf("<QRexpire_mode>%d</QRexpire_mode>\n", buf->QRep.expire_mode);
-       cprintf("<QRexpire_value>%d</QRexpire_value>\n", buf->QRep.expire_value);
-       cprintf("<QRnumber>%ld</QRnumber>\n", buf->QRnumber);
-       cprintf("<QRorder>%d</QRorder>\n", buf->QRorder);
-       cprintf("<QRflags2>%u</QRflags2>\n", buf->QRflags2);
-       cprintf("<QRdefaultview>%d</QRdefaultview>\n", buf->QRdefaultview);
-       cprintf("<msgnum_info>%ld</msgnum_info>\n", buf->msgnum_info);
-       cprintf("<msgnum_pic>%ld</msgnum_pic>\n", buf->msgnum_pic);
-       client_write(HKEY("</room>\n"));
-
-       // message list goes inside this tag
-       CtdlGetRoom(&CC->room, buf->QRname);
-       client_write(HKEY("<room_messages>"));
-       client_write(HKEY("<FRname>"));
-       xml_strout(buf->QRname);                        // buf->QRname rather than CC->room.QRname to guarantee consistency
-       client_write(HKEY("</FRname>\n"));
-       client_write(HKEY("<FRmsglist>\n"));
-       CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, migr_export_room_msg, NULL);
-       client_write(HKEY("</FRmsglist>\n"));
-       client_write(HKEY("</room_messages>\n"));
-}
-
-
-void migr_export_rooms(void) {
-       char cmd[SIZ];
-       migr_global_message_list = fopen(migr_tempfilename1, "w");
-       if (migr_global_message_list != NULL) {
-               CtdlForEachRoom(migr_export_rooms_backend, NULL);
-               fclose(migr_global_message_list);
-       }
-
-       // Process the 'global' message list.  (Sort it and remove dups.
-       // Dups are ok because a message may be in more than one room, but
-       // this will be handled by exporting the reference count, not by
-       // exporting the message multiple times.)
-       snprintf(cmd, sizeof cmd, "sort -n <%s >%s", migr_tempfilename1, migr_tempfilename2);
-       if (system(cmd) != 0) {
-               syslog(LOG_ERR, "migrate: error %d", errno);
-       }
-       snprintf(cmd, sizeof cmd, "uniq <%s >%s", migr_tempfilename2, migr_tempfilename1);
-       if (system(cmd) != 0) {
-               syslog(LOG_ERR, "migrate: error %d", errno);
-       }
-
-       snprintf(cmd, sizeof cmd, "wc -l %s", migr_tempfilename1);
-       FILE *fp = popen(cmd, "r");
-       if (fp) {
-               fgets(cmd, sizeof cmd, fp);
-               pclose(fp);
-               total_msgs = atoi(cmd);
-       }
-       else {
-               total_msgs = 1; // any nonzero just to keep it from barfing
-       }
-       syslog(LOG_DEBUG, "migrate: total messages to be exported: %d", total_msgs);
-}
-
-
-void migr_export_floors(void) {
-        struct floor qfbuf, *buf;
-        int i;
-
-        for (i=0; i < MAXFLOORS; ++i) {
-               client_write(HKEY("<floor>\n"));
-               cprintf("<f_num>%d</f_num>\n", i);
-                CtdlGetFloor(&qfbuf, i);
-               buf = &qfbuf;
-               cprintf("<f_flags>%u</f_flags>\n", buf->f_flags);
-               client_write(HKEY("<f_name>")); xml_strout(buf->f_name); client_write(HKEY("</f_name>\n"));
-               cprintf("<f_ref_count>%d</f_ref_count>\n", buf->f_ref_count);
-               cprintf("<f_ep_expire_mode>%d</f_ep_expire_mode>\n", buf->f_ep.expire_mode);
-               cprintf("<f_ep_expire_value>%d</f_ep_expire_value>\n", buf->f_ep.expire_value);
-               client_write(HKEY("</floor>\n"));
-       }
-}
-
-
-// Return nonzero if the supplied string contains only characters which are valid in a sequence set.
-int is_sequence_set(char *s) {
-       if (!s) return(0);
-
-       char *c = s;
-       char ch;
-       while (ch = *c++, ch) {
-               if (!strchr("0123456789*,:", ch)) {
-                       return(0);
-               }
-       }
-       return(1);
-}
-
-
-// Traverse the visits file...
-void migr_export_visits(void) {
-       struct visit vbuf;
-       struct cdbdata *cdbv;
-
-       cdb_rewind(CDB_VISIT);
-
-       while (cdbv = cdb_next_item(CDB_VISIT), cdbv != NULL) {
-               memset(&vbuf, 0, sizeof(struct visit));
-               memcpy(&vbuf, cdbv->ptr,
-                      ((cdbv->len > sizeof(struct visit)) ?
-                       sizeof(struct visit) : cdbv->len));
-               cdb_free(cdbv);
-
-               client_write(HKEY("<visit>\n"));
-               cprintf("<v_roomnum>%ld</v_roomnum>\n", vbuf.v_roomnum);
-               cprintf("<v_roomgen>%ld</v_roomgen>\n", vbuf.v_roomgen);
-               cprintf("<v_usernum>%ld</v_usernum>\n", vbuf.v_usernum);
-
-               client_write(HKEY("<v_seen>"));
-               if ( (!IsEmptyStr(vbuf.v_seen)) && (is_sequence_set(vbuf.v_seen)) ) {
-                       xml_strout(vbuf.v_seen);
-               }
-               else {
-                       cprintf("%ld", vbuf.v_lastseen);
-               }
-               client_write(HKEY("</v_seen>"));
-
-               if ( (!IsEmptyStr(vbuf.v_answered)) && (is_sequence_set(vbuf.v_answered)) ) {
-                       client_write(HKEY("<v_answered>"));
-                       xml_strout(vbuf.v_answered);
-                       client_write(HKEY("</v_answered>\n"));
-               }
-
-               cprintf("<v_flags>%u</v_flags>\n", vbuf.v_flags);
-               cprintf("<v_view>%d</v_view>\n", vbuf.v_view);
-               client_write(HKEY("</visit>\n"));
-       }
-}
-
-
-void migr_export_message(long msgnum) {
-       struct MetaData smi;
-       struct CtdlMessage *msg;
-       struct ser_ret smr;
-       long bytes_written = 0;
-       long this_block = 0;
-
-       // We can use a static buffer here because there will never be more than
-       // one of this operation happening at any given time, and it's really best
-       // to just keep it allocated once instead of torturing malloc/free.
-       // Call this function with msgnum "-1" to free the buffer when finished.
-
-       static int encoded_alloc = 0;
-       static char *encoded_msg = NULL;
-
-       if (msgnum < 0) {
-               if ((encoded_alloc == 0) && (encoded_msg != NULL)) {
-                       free(encoded_msg);
-                       encoded_alloc = 0;
-                       encoded_msg = NULL;
-               }
-               return;
-       }
-
-       // Ok, here we go ...
-
-       msg = CtdlFetchMessage(msgnum, 1);
-       if (msg == NULL) return;                                // fail silently
-
-       client_write(HKEY("<message>\n"));
-       GetMetaData(&smi, msgnum);
-       cprintf("<msg_msgnum>%ld</msg_msgnum>\n", msgnum);
-       cprintf("<msg_meta_refcount>%d</msg_meta_refcount>\n", smi.meta_refcount);
-       cprintf("<msg_meta_rfc822_length>%ld</msg_meta_rfc822_length>\n", smi.meta_rfc822_length);
-       client_write(HKEY("<msg_meta_content_type>")); xml_strout(smi.meta_content_type); client_write(HKEY("</msg_meta_content_type>\n"));
-
-       client_write(HKEY("<msg_text>"));
-       CtdlSerializeMessage(&smr, msg);
-       CM_Free(msg);
-
-       // Predict the buffer size we need.  Expand the buffer if necessary.
-       int encoded_len = smr.len * 15 / 10 ;
-       if (encoded_len > encoded_alloc) {
-               encoded_alloc = encoded_len;
-               encoded_msg = realloc(encoded_msg, encoded_alloc);
-       }
-
-       if (encoded_msg == NULL) {
-               // Questionable hack that hopes it'll work next time and we only lose one message
-               encoded_alloc = 0;
-       }
-       else {
-               // Once we do the encoding we know the exact size
-               encoded_len = CtdlEncodeBase64(encoded_msg, (char *)smr.ser, smr.len, BASE64_YES_LINEBREAKS);
-
-               // Careful now.  If the message is gargantuan, trying to write multiple gigamegs in one
-               // big write operation can make our transport unhappy.  So we'll chunk it up 10 KB at a time.
-               bytes_written = 0;
-               while ( (bytes_written < encoded_len) && (!server_shutting_down) ) {
-                       this_block = encoded_len - bytes_written;
-                       if (this_block > 10240) {
-                               this_block = 10240;
-                       }
-                       client_write(&encoded_msg[bytes_written], this_block);
-                       bytes_written += this_block;
-               }
-       }
-
-       free(smr.ser);
-
-       client_write(HKEY("</msg_text>\n"));
-       client_write(HKEY("</message>\n"));
-}
-
-
-void migr_export_configs(void) {
-       struct cdbdata *cdbcfg;
-       int keylen = 0;
-       char *key = NULL;
-       char *value = NULL;
-
-       cdb_rewind(CDB_CONFIG);
-       while (cdbcfg = cdb_next_item(CDB_CONFIG), cdbcfg != NULL) {
-
-               keylen = strlen(cdbcfg->ptr);
-               key = cdbcfg->ptr;
-               value = cdbcfg->ptr + keylen + 1;
-
-               client_write("<config key=\"", 13);
-               xml_strout(key);
-               client_write("\">", 2);
-               xml_strout(value);
-               client_write("</config>\n", 10);
-               cdb_free(cdbcfg);
-       }
-}
-
-
-void migr_export_messages(void) {
-       char buf[SIZ];
-       long msgnum;
-       int count = 0;
-       int progress = 0;
-       int prev_progress = 0;
-       CitContext *Ctx;
-
-       Ctx = CC;
-       migr_global_message_list = fopen(migr_tempfilename1, "r");
-       if (migr_global_message_list != NULL) {
-               syslog(LOG_INFO, "migrate: opened %s", migr_tempfilename1);
-               while ((Ctx->kill_me == 0) && 
-                      (fgets(buf, sizeof(buf), migr_global_message_list) != NULL)) {
-                       msgnum = atol(buf);
-                       if (msgnum > 0L) {
-                               migr_export_message(msgnum);
-                               ++count;
-                       }
-                       progress = (count * 74 / total_msgs) + 25 ;
-                       if ((progress > prev_progress) && (progress < 100)) {
-                               cprintf("<progress>%d</progress>\n", progress);
-                       }
-                       prev_progress = progress;
-               }
-               fclose(migr_global_message_list);
-       }
-       if (Ctx->kill_me == 0) {
-               syslog(LOG_INFO, "migrate: exported %d messages.", count);
-       }
-       else {
-               syslog(LOG_ERR, "migrate: export aborted due to client disconnect!");
-       }
-
-       migr_export_message(-1L);       // This frees the encoding buffer
-}
-
-
-void migr_do_export(void) {
-       CitContext *Ctx;
-
-       Ctx = CC;
-       cprintf("%d Exporting all Citadel databases.\n", LISTING_FOLLOWS);
-       Ctx->dont_term = 1;
-
-       client_write(HKEY("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"));
-       client_write(HKEY("<citadel_migrate_data>\n"));
-       cprintf("<version>%d</version>\n", REV_LEVEL);
-       cprintf("<progress>%d</progress>\n", 0);
-
-       // export the configuration database
-       migr_export_configs();
-       cprintf("<progress>%d</progress>\n", 2);
-       
-       if (Ctx->kill_me == 0)  migr_export_users();
-       cprintf("<progress>%d</progress>\n", 7);
-       cprintf("<progress>%d</progress>\n", 12);
-       if (Ctx->kill_me == 0)  migr_export_rooms();
-       cprintf("<progress>%d</progress>\n", 17);
-       if (Ctx->kill_me == 0)  migr_export_floors();
-       cprintf("<progress>%d</progress>\n", 18);
-       if (Ctx->kill_me == 0)  migr_export_visits();
-       cprintf("<progress>%d</progress>\n", 25);
-       if (Ctx->kill_me == 0)  migr_export_messages();
-       cprintf("<progress>%d</progress>\n", 100);
-       client_write(HKEY("</citadel_migrate_data>\n"));
-       client_write(HKEY("000\n"));
-       Ctx->dont_term = 0;
-}
-
-
-//                              Import code
-//   Here's the code that implements the import side.  It's going to end up
-//       being one big loop with lots of global variables.  I don't care.
-// You wouldn't run multiple concurrent imports anyway.  If this offends your
-//  delicate sensibilities  then go rewrite it in Ruby on Rails or something.
-
-
-int citadel_migrate_data = 0;          // Are we inside a <citadel_migrate_data> tag pair?
-StrBuf *migr_chardata = NULL;
-StrBuf *migr_MsgData = NULL;
-struct ctdluser usbuf;
-struct ctdlroom qrbuf;
-char FRname[ROOMNAMELEN];
-struct floor flbuf;
-int floornum = 0;
-struct visit vbuf;
-struct MetaData smi;
-long import_msgnum = 0;
-
-// This callback stores up the data which appears in between tags.
-void migr_xml_chardata(void *data, const XML_Char *s, int len) {
-       StrBufAppendBufPlain(migr_chardata, s, len, 0);
-}
-
-
-void migr_xml_start(void *data, const char *el, const char **attr) {
-       int i;
-
-       //  *** GENERAL STUFF ***
-
-       // Reset chardata_len to zero and init buffer
-       FlushStrBuf(migr_chardata);
-       FlushStrBuf(migr_MsgData);
-
-       if (!strcasecmp(el, "citadel_migrate_data")) {
-               ++citadel_migrate_data;
-
-               // As soon as it looks like the input data is a genuine Citadel XML export,
-               // whack the existing database on disk to make room for the new one.
-               if (citadel_migrate_data == 1) {
-                       syslog(LOG_INFO, "migrate: erasing existing databases so we can receive the incoming import");
-                       for (i = 0; i < MAXCDB; ++i) {
-                               cdb_trunc(i);
-                       }
-               }
-               return;
-       }
-
-       if (citadel_migrate_data != 1) {
-               syslog(LOG_ERR, "migrate: out-of-sequence tag <%s> detected.  Warning: ODD-DATA!", el);
-               return;
-       }
-
-       // When we begin receiving XML for one of these record types, clear out the associated
-       // buffer so we don't accidentally carry over any data from a previous record.
-       if (!strcasecmp(el, "user"))                    memset(&usbuf, 0, sizeof(struct ctdluser));
-       else if (!strcasecmp(el, "room"))               memset(&qrbuf, 0, sizeof(struct ctdlroom));
-       else if (!strcasecmp(el, "room_messages"))      memset(FRname, 0, sizeof FRname);
-       else if (!strcasecmp(el, "floor"))              memset(&flbuf, 0, sizeof(struct floor));
-       else if (!strcasecmp(el, "visit"))              memset(&vbuf, 0, sizeof(struct visit));
-
-       else if (!strcasecmp(el, "message")) {
-               memset(&smi, 0, sizeof (struct MetaData));
-               import_msgnum = 0;
-       }
-       else if (!strcasecmp(el, "config")) {
-               if (ikey != NULL) {
-                       free(ikey);
-                       ikey = NULL;
-               }
-               while (*attr) {
-                       if (!strcasecmp(attr[0], "key")) {
-                               ikey = strdup(attr[1]);
-                       }
-                       attr += 2;
-               }
-       }
-
-}
-
-
-int migr_userrecord(void *data, const char *el) {
-       if (!strcasecmp(el, "u_version"))                       usbuf.version = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "u_uid"))                      usbuf.uid = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "u_password"))                 safestrncpy(usbuf.password, ChrPtr(migr_chardata), sizeof usbuf.password);
-       else if (!strcasecmp(el, "u_flags"))                    usbuf.flags = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "u_axlevel"))                  usbuf.axlevel = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "u_usernum"))                  usbuf.usernum = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "u_lastcall"))                 usbuf.lastcall = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "u_USuserpurge"))              usbuf.USuserpurge = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "u_fullname"))                 safestrncpy(usbuf.fullname, ChrPtr(migr_chardata), sizeof usbuf.fullname);
-       else if (!strcasecmp(el, "u_msgnum_bio"))               usbuf.msgnum_bio = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "u_msgnum_pic"))               usbuf.msgnum_pic = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "u_emailaddrs"))               safestrncpy(usbuf.emailaddrs, ChrPtr(migr_chardata), sizeof usbuf.emailaddrs);
-       else if (!strcasecmp(el, "u_msgnum_inboxrules"))        usbuf.msgnum_inboxrules = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "u_lastproc_inboxrules"))      usbuf.lastproc_inboxrules = atol(ChrPtr(migr_chardata));
-       else return 0;
-       return 1;
-}
-
-
-int migr_roomrecord(void *data, const char *el) {
-       if (!strcasecmp(el, "QRname"))                          safestrncpy(qrbuf.QRname, ChrPtr(migr_chardata), sizeof qrbuf.QRname);
-       else if (!strcasecmp(el, "QRpasswd"))                   safestrncpy(qrbuf.QRpasswd, ChrPtr(migr_chardata), sizeof qrbuf.QRpasswd);
-       else if (!strcasecmp(el, "QRroomaide"))                 qrbuf.QRroomaide = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "QRhighest"))                  qrbuf.QRhighest = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "QRgen"))                      qrbuf.QRgen = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "QRflags"))                    qrbuf.QRflags = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "QRdirname"))                  safestrncpy(qrbuf.QRdirname, ChrPtr(migr_chardata), sizeof qrbuf.QRdirname);
-       else if (!strcasecmp(el, "QRfloor"))                    qrbuf.QRfloor = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "QRmtime"))                    qrbuf.QRmtime = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "QRexpire_mode"))              qrbuf.QRep.expire_mode = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "QRexpire_value"))             qrbuf.QRep.expire_value = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "QRnumber"))                   qrbuf.QRnumber = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "QRorder"))                    qrbuf.QRorder = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "QRflags2"))                   qrbuf.QRflags2 = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "QRdefaultview"))              qrbuf.QRdefaultview = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "msgnum_info"))                qrbuf.msgnum_info = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "msgnum_pic"))                 qrbuf.msgnum_pic = atol(ChrPtr(migr_chardata));
-       else return 0;
-       return 1;
-}
-
-
-int migr_floorrecord(void *data, const char *el) {
-       if (!strcasecmp(el, "f_num"))                           floornum = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "f_flags"))                    flbuf.f_flags = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "f_name"))                     safestrncpy(flbuf.f_name, ChrPtr(migr_chardata), sizeof flbuf.f_name);
-       else if (!strcasecmp(el, "f_ref_count"))                flbuf.f_ref_count = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "f_ep_expire_mode"))           flbuf.f_ep.expire_mode = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "f_ep_expire_value"))          flbuf.f_ep.expire_value = atoi(ChrPtr(migr_chardata));
-       else return 0;
-       return 1;
-}
-
-
-int migr_visitrecord(void *data, const char *el) {
-       if (!strcasecmp(el, "v_roomnum"))                       vbuf.v_roomnum = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "v_roomgen"))                  vbuf.v_roomgen = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "v_usernum"))                  vbuf.v_usernum = atol(ChrPtr(migr_chardata));
-
-       else if (!strcasecmp(el, "v_seen")) {
-               int is_textual_seen = 0;
-               int i;
-               int max = StrLength(migr_chardata);
-
-               vbuf.v_lastseen = atol(ChrPtr(migr_chardata));
-               is_textual_seen = 0;
-               for (i=0; i < max; ++i) 
-                       if (!isdigit(ChrPtr(migr_chardata)[i]))
-                               is_textual_seen = 1;
-               if (is_textual_seen)
-                       safestrncpy(vbuf.v_seen, ChrPtr(migr_chardata), sizeof vbuf.v_seen);
-       }
-
-       else if (!strcasecmp(el, "v_answered"))                 safestrncpy(vbuf.v_answered, ChrPtr(migr_chardata), sizeof vbuf.v_answered);
-       else if (!strcasecmp(el, "v_flags"))                    vbuf.v_flags = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "v_view"))                     vbuf.v_view = atoi(ChrPtr(migr_chardata));
-       else return 0;
-       return 1;
-}
-
-
-void migr_xml_end(void *data, const char *el) {
-       const char *ptr;
-       int msgcount = 0;
-       long msgnum = 0L;
-       long *msglist = NULL;
-       int msglist_alloc = 0;
-       // *** GENERAL STUFF ***
-
-       if (!strcasecmp(el, "citadel_migrate_data")) {
-               --citadel_migrate_data;
-               return;
-       }
-
-       if (citadel_migrate_data != 1) {
-               syslog(LOG_ERR, "migrate: out-of-sequence tag <%s> detected.  Warning: ODD-DATA!", el);
-               return;
-       }
-
-       // syslog(LOG_DEBUG, "END TAG: <%s> DATA: <%s>\n", el, (migr_chardata_len ? migr_chardata : ""));
-
-       // *** CONFIG ***
-
-       if (!strcasecmp(el, "config")) {
-               syslog(LOG_DEBUG, "migrate: imported config key=%s", ikey);
-
-               if (ikey != NULL) {
-                       CtdlSetConfigStr(ikey, (char *)ChrPtr(migr_chardata));
-                       free(ikey);
-                       ikey = NULL;
-               }
-               else {
-                       syslog(LOG_INFO, "migrate: closed a <config> tag but no key name was supplied.");
-               }
-       }
-
-       // *** USER ***
-       else if ((!strncasecmp(el, HKEY("u_"))) && 
-                migr_userrecord(data, el))
-               ; /* Nothing to do anymore */
-       else if (!strcasecmp(el, "user")) {
-               CtdlPutUser(&usbuf);
-               syslog(LOG_INFO, "migrate: imported user: %s", usbuf.fullname);
-       }
-
-       // *** ROOM ***
-       else if ((!strncasecmp(el, HKEY("QR"))) && 
-                migr_roomrecord(data, el))
-               ; // Nothing to do anymore
-       else if (!strcasecmp(el, "room")) {
-               CtdlPutRoom(&qrbuf);
-               syslog(LOG_INFO, "migrate: imported room: %s", qrbuf.QRname);
-       }
-
-       // *** ROOM MESSAGE POINTERS ***
-
-       else if (!strcasecmp(el, "FRname")) {
-               safestrncpy(FRname, ChrPtr(migr_chardata), sizeof FRname);
-       }
-
-       else if (!strcasecmp(el, "FRmsglist")) {
-               if (!IsEmptyStr(FRname)) {
-                       msgcount = 0;
-                       msglist_alloc = 1000;
-                       msglist = malloc(sizeof(long) * msglist_alloc);
-
-                       syslog(LOG_DEBUG, "migrate: message list for: %s", FRname);
-
-                       ptr = ChrPtr(migr_chardata);
-                       while (*ptr != 0) {
-                               while ((*ptr != 0) && (!isdigit(*ptr))) {
-                                       ++ptr;
-                               }
-                               if ((*ptr != 0) && (isdigit(*ptr))) {
-                                       msgnum = atol(ptr);
-                                       if (msgnum > 0L) {
-                                               if (msgcount >= msglist_alloc) {
-                                                       msglist_alloc *= 2;
-                                                       msglist = realloc(msglist, sizeof(long) * msglist_alloc);
-                                               }
-                                               msglist[msgcount++] = msgnum;
-                                               }
-                                       }
-                                       while ((*ptr != 0) && (isdigit(*ptr))) {
-                                               ++ptr;
-                                       }
-                               }
-                       }
-                       if (msgcount > 0) {
-                               CtdlSaveMsgPointersInRoom(FRname, msglist, msgcount, 0, NULL, 1);
-                       }
-                       free(msglist);
-                       msglist = NULL;
-                       msglist_alloc = 0;
-                       syslog(LOG_DEBUG, "migrate: imported %d messages.", msgcount);
-                       if (server_shutting_down) {
-                               return;
-               }
-       }
-
-       // *** FLOORS ***
-       else if ((!strncasecmp(el, HKEY("f_"))) && 
-                migr_floorrecord(data, el))
-               ; // Nothing to do anymore
-
-       else if (!strcasecmp(el, "floor")) {
-               CtdlPutFloor(&flbuf, floornum);
-               syslog(LOG_INFO, "migrate: imported floor #%d (%s)", floornum, flbuf.f_name);
-       }
-
-       // *** VISITS ***
-       else if ((!strncasecmp(el, HKEY("v_"))) && migr_visitrecord(data, el)) {
-               ; // Nothing to do anymore
-       }
-       else if (!strcasecmp(el, "visit")) {
-               put_visit(&vbuf);
-               syslog(LOG_INFO, "migrate: imported visit: %ld/%ld/%ld", vbuf.v_roomnum, vbuf.v_roomgen, vbuf.v_usernum);
-       }
-
-       // *** MESSAGES ***
-       
-       else if (!strcasecmp(el, "msg_msgnum"))                 smi.meta_msgnum = import_msgnum = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "msg_meta_refcount"))          smi.meta_refcount = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "msg_meta_rfc822_length"))     smi.meta_rfc822_length = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "msg_meta_content_type"))      safestrncpy(smi.meta_content_type, ChrPtr(migr_chardata), sizeof smi.meta_content_type);
-
-       else if (!strcasecmp(el, "msg_text")) {
-               long rc;
-               struct CtdlMessage *msg;
-
-               FlushStrBuf(migr_MsgData);
-               StrBufDecodeBase64To(migr_chardata, migr_MsgData);
-
-               msg = CtdlDeserializeMessage(import_msgnum, -1,
-                                            ChrPtr(migr_MsgData), 
-                                            StrLength(migr_MsgData));
-               if (msg != NULL) {
-                       rc = CtdlSaveThisMessage(msg, import_msgnum, 0);
-                       if (rc == 0) {
-                               PutMetaData(&smi);
-                       }
-                       CM_Free(msg);
-               }
-               else {
-                       rc = -1;
-               }
-
-               syslog(LOG_INFO,
-                      "migrate: %s message #%ld, size=%d, ref=%d, body=%ld, content-type: %s",
-                      (rc!= 0)?"failed to import":"imported",
-                      import_msgnum,
-                      StrLength(migr_MsgData),
-                      smi.meta_refcount,
-                      smi.meta_rfc822_length,
-                      smi.meta_content_type
-               );
-               memset(&smi, 0, sizeof(smi));
-       }
-
-       // *** MORE GENERAL STUFF ***
-
-       FlushStrBuf(migr_chardata);
-}
-
-
-// Import begins here
-void migr_do_import(void) {
-       XML_Parser xp;
-       char buf[SIZ];
-       
-       unbuffer_output();
-       migr_chardata = NewStrBufPlain(NULL, SIZ * 20);
-       migr_MsgData = NewStrBufPlain(NULL, SIZ * 20);
-       xp = XML_ParserCreate(NULL);
-       if (!xp) {
-               cprintf("%d Failed to create XML parser instance\n", ERROR+INTERNAL_ERROR);
-               return;
-       }
-       XML_SetElementHandler(xp, migr_xml_start, migr_xml_end);
-       XML_SetCharacterDataHandler(xp, migr_xml_chardata);
-
-       CC->dont_term = 1;
-
-       cprintf("%d sock it to me\n", SEND_LISTING);
-       unbuffer_output();
-
-       client_set_inbound_buf(SIZ * 10);
-
-       while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) {
-               XML_Parse(xp, buf, strlen(buf), 0);
-               if (server_shutting_down)
-                       break;  // Should we break or return?
-       }
-
-       XML_Parse(xp, "", 0, 1);
-       XML_ParserFree(xp);
-       FreeStrBuf(&migr_chardata);
-       FreeStrBuf(&migr_MsgData);
-       rebuild_euid_index();
-       rebuild_usersbynumber();
-       CtdlSetConfigInt("MM_fulltext_wordbreaker", -1);        // Set an invalid wordbreaker to force re-indexing
-       CtdlRebuildDirectoryIndex();                            // Force a rebuild of the directory index
-       CC->dont_term = 0;
-}
-
-
-// ******************************************************************************
-// *                         Dispatcher, Common code                            *
-// ******************************************************************************
-
-// Dump out the pathnames of directories which can be copied "as is"
-void migr_do_listdirs(void) {
-       cprintf("%d Don't forget these:\n", LISTING_FOLLOWS);
-       cprintf("files|%s\n",           ctdl_file_dir);
-       cprintf("messages|%s\n",        ctdl_message_dir);
-       cprintf("keys|%s\n",            ctdl_key_dir);
-       cprintf("000\n");
-}
-
-
-// ******************************************************************************
-// *                    Repair database integrity                               *
-// ******************************************************************************
-
-StrBuf *PlainMessageBuf = NULL;
-HashList *UsedMessageIDS = NULL;
-
-int migr_restore_message_metadata(long msgnum, int refcount) {
-       struct MetaData smi;
-       struct CtdlMessage *msg;
-       char *mptr = NULL;
-
-       // We can use a static buffer here because there will never be more than
-       // one of this operation happening at any given time, and it's really best
-       // to just keep it allocated once instead of torturing malloc/free.
-       // Call this function with msgnum "-1" to free the buffer when finished.
-       static int encoded_alloc = 0;
-       static char *encoded_msg = NULL;
-
-       if (msgnum < 0) {
-               if ((encoded_alloc == 0) && (encoded_msg != NULL)) {
-                       free(encoded_msg);
-                       encoded_alloc = 0;
-                       encoded_msg = NULL;
-                       // todo FreeStrBuf(&PlainMessageBuf); PlainMessageBuf = NULL;
-               }
-               return 0;
-       }
-
-       if (PlainMessageBuf == NULL) {
-               PlainMessageBuf = NewStrBufPlain(NULL, 10*SIZ);
-       }
-
-       // Ok, here we go ...
-
-       msg = CtdlFetchMessage(msgnum, 1);
-       if (msg == NULL) {
-               return 1;
-       }
-
-       GetMetaData(&smi, msgnum);
-       smi.meta_msgnum = msgnum;
-       smi.meta_refcount = refcount;
-       
-       // restore the content type from the message body:
-       mptr = bmstrcasestr(msg->cm_fields[eMesageText], "Content-type:");
-       if (mptr != NULL) {
-               char *aptr;
-               safestrncpy(smi.meta_content_type, &mptr[13], sizeof smi.meta_content_type);
-               string_trim(smi.meta_content_type);
-               aptr = smi.meta_content_type;
-               while (!IsEmptyStr(aptr)) {
-                       if ((*aptr == ';')
-                           || (*aptr == ' ')
-                           || (*aptr == 13)
-                           || (*aptr == 10)) {
-                               memset(aptr, 0, sizeof(smi.meta_content_type) - (aptr - smi.meta_content_type));
-                       }
-                       else aptr++;
-               }
-       }
-
-       CC->redirect_buffer = PlainMessageBuf;
-       CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1, QP_EADDR);
-       smi.meta_rfc822_length = StrLength(CC->redirect_buffer);
-       CC->redirect_buffer = NULL;
-
-       syslog(LOG_INFO,
-              "migrate: setting message #%ld meta data to: refcount=%d, bodylength=%ld, content-type: %s",
-              smi.meta_msgnum,
-              smi.meta_refcount,
-              smi.meta_rfc822_length,
-              smi.meta_content_type
-       );
-
-       PutMetaData(&smi);
-       CM_Free(msg);
-       return 0;
-}
-
-
-void migr_check_room_msg(long msgnum, void *userdata) {
-       fprintf(migr_global_message_list, "%ld %s\n", msgnum, CC->room.QRname);
-}
-
-
-void migr_check_rooms_backend(struct ctdlroom *buf, void *data) {
-       // message list goes inside this tag
-       CtdlGetRoom(&CC->room, buf->QRname);
-       CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, migr_check_room_msg, NULL);
-}
-
-
-void RemoveMessagesFromRooms(StrBuf *RoomNameVec, long msgnum) {
-       struct MetaData smi;
-       const char *Pos = NULL;
-       StrBuf *oneRoom = NewStrBuf();
-
-       syslog(LOG_INFO, "migrate: removing message pointer %ld from these rooms: %s", msgnum, ChrPtr(RoomNameVec));
-
-       while (Pos != StrBufNOTNULL){
-               StrBufExtract_NextToken(oneRoom, RoomNameVec, &Pos, '|');
-               CtdlDeleteMessages(ChrPtr(oneRoom), &msgnum, 1, "");
-       };
-       GetMetaData(&smi, msgnum);
-       AdjRefCount(msgnum, -smi.meta_refcount);
-}
-
-
-void migr_do_restore_meta(void) {
-       char buf[SIZ];
-       int failGetMessage;
-       long msgnum = 0;
-       int lastnum = 0;
-       int refcount = 0;
-       CitContext *Ctx;
-       char *prn;
-       StrBuf *RoomNames;
-       char cmd[SIZ];
-
-       migr_global_message_list = fopen(migr_tempfilename1, "w");
-       if (migr_global_message_list != NULL) {
-               CtdlForEachRoom(migr_check_rooms_backend, NULL);
-               fclose(migr_global_message_list);
-       }
-
-       // Process the 'global' message list.  (Sort it and remove dups.
-       // Dups are ok because a message may be in more than one room, but
-       // this will be handled by exporting the reference count, not by
-       // exporting the message multiple times.)
-       snprintf(cmd, sizeof cmd, "sort -n <%s >%s", migr_tempfilename1, migr_tempfilename2);
-       if (system(cmd) != 0) {
-               syslog(LOG_ERR, "migrate: error %d", errno);
-       }
-
-       RoomNames = NewStrBuf();
-       Ctx = CC;
-       migr_global_message_list = fopen(migr_tempfilename2, "r");
-       if (migr_global_message_list != NULL) {
-               syslog(LOG_INFO, "migrate: opened %s", migr_tempfilename1);
-               while ((Ctx->kill_me == 0) && 
-                      (fgets(buf, sizeof(buf), migr_global_message_list) != NULL)) {
-                       msgnum = atol(buf);
-                       if (msgnum == 0L) 
-                               continue;
-                       if (lastnum == 0) {
-                               lastnum = msgnum;
-                       }
-                       prn = strchr(buf, ' ');
-                       if (lastnum != msgnum) {
-                               failGetMessage = migr_restore_message_metadata(lastnum, refcount);
-                               if (failGetMessage) {
-                                       RemoveMessagesFromRooms(RoomNames, lastnum);
-                               }
-                               refcount = 1;
-                               lastnum = msgnum;
-                               if (prn != NULL) {
-                                       StrBufPlain(RoomNames, prn + 1, -1);
-                               }
-                               StrBufTrim(RoomNames);
-                       }
-                       else {
-                               if (prn != NULL) {
-                                       if (StrLength(RoomNames) > 0) {
-                                               StrBufAppendBufPlain(RoomNames, HKEY("|"), 0);
-                                       }
-                                       StrBufAppendBufPlain(RoomNames, prn, -1, 1);
-                                       StrBufTrim(RoomNames);
-                               }
-                               refcount ++;
-                       }
-                       lastnum = msgnum;
-               }
-               failGetMessage = migr_restore_message_metadata(msgnum, refcount);
-               if (failGetMessage) {
-                       RemoveMessagesFromRooms(RoomNames, lastnum);
-               }
-               fclose(migr_global_message_list);
-       }
-
-       migr_restore_message_metadata(-1L, -1); // This frees the encoding buffer
-       cprintf("%d system analysis completed", CIT_OK);
-       Ctx->kill_me = 1;
-}
-
-
-// ******************************************************************************
-// *                         Dispatcher, Common code                            *
-// ******************************************************************************
-void cmd_migr(char *cmdbuf) {
-       char cmd[32];
-       
-       if (CtdlAccessCheck(ac_aide)) return;
-       
-       if (CtdlTrySingleUser()) {
-               CtdlDisableHouseKeeping();
-               CtdlMakeTempFileName(migr_tempfilename1, sizeof migr_tempfilename1);
-               CtdlMakeTempFileName(migr_tempfilename2, sizeof migr_tempfilename2);
-
-               extract_token(cmd, cmdbuf, 0, '|', sizeof cmd);
-               if (!strcasecmp(cmd, "export")) {
-                       migr_do_export();
-               }
-               else if (!strcasecmp(cmd, "import")) {
-                       migr_do_import();
-               }
-               else if (!strcasecmp(cmd, "listdirs")) {
-                       migr_do_listdirs();
-               }
-               else if (!strcasecmp(cmd, "restoremeta")) {
-                       migr_do_restore_meta();
-               }
-               else {
-                       cprintf("%d illegal command\n", ERROR + ILLEGAL_VALUE);
-               }
-
-               unlink(migr_tempfilename1);
-               unlink(migr_tempfilename2);
-
-               CtdlEnableHouseKeeping();
-               CtdlEndSingleUser();
-       }
-       else {
-               cprintf("%d The migrator is already running.\n", ERROR + RESOURCE_BUSY);
-       }
-}
-
-
-// Initialization function, called from modules_init.c
-char *ctdl_module_init_migrate() {
-       if (!threading) {
-               CtdlRegisterProtoHook(cmd_migr, "MIGR", "Across-the-wire migration");
-       }
-       
-       // return our module name for the log
-       return "migrate";
-}
index a79f6d326e4b621c153a8f3edb4492290d5c30a4..c405c311a89dc4147b74242e08e92ab4cff6ae37 100644 (file)
@@ -51,7 +51,6 @@ void initialize_modules(int is_threading) {
        syslog(LOG_DEBUG, "extensions: init %s", ctdl_module_init_instmsg());
        syslog(LOG_DEBUG, "extensions: init %s", ctdl_module_init_listdeliver());
        syslog(LOG_DEBUG, "extensions: init %s", ctdl_module_init_listsub());
-       syslog(LOG_DEBUG, "extensions: init %s", ctdl_module_init_migrate());
        syslog(LOG_DEBUG, "extensions: init %s", ctdl_module_init_nntp());
        syslog(LOG_DEBUG, "extensions: init %s", ctdl_module_init_notes());
        syslog(LOG_DEBUG, "extensions: init %s", ctdl_module_init_pop3());
diff --git a/citadel/utils/ctdlmigrate.c b/citadel/utils/ctdlmigrate.c
deleted file mode 100644 (file)
index 6b1af02..0000000
+++ /dev/null
@@ -1,453 +0,0 @@
-// Across-the-wire migration utility for Citadel
-//
-// Copyright (c) 2009-2022 citadel.org
-//
-// This program is open source software.  Use, duplication, or disclosure
-// is subject to the terms of the GNU General Public License, version 3.
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/utsname.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <netdb.h>
-#include <errno.h>
-#include <limits.h>
-#include <pwd.h>
-#include <time.h>
-#include <readline/readline.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <libcitadel.h>
-#include "../server/citadel_defs.h"
-#include "axdefs.h"
-#include "../server/sysdep.h"
-#include "../server/config.h"
-#include "../server/citadel_dirs.h"
-
-
-// support for getz() -- (globals would not be appropriate in a multithreaded program)
-static int gmaxlen = 0;
-static char *gdeftext = NULL;
-
-
-// support function for getz()
-static int limit_rl(FILE *dummy) {
-       if (rl_end > gmaxlen) {
-               return '\b';
-       }
-       return rl_getc(dummy);
-}
-
-
-// support function for getz()
-static int getz_deftext(void) {
-       if (gdeftext) {
-               rl_insert_text(gdeftext);
-               gdeftext = NULL;
-               rl_startup_hook = NULL;
-       }
-       return 0;
-}
-
-
-// Replacement for gets() that uses libreadline.
-void getz(char *buf, int maxlen, char *default_value, char *prompt) {
-       rl_startup_hook = getz_deftext;
-       rl_getc_function = limit_rl;
-       gmaxlen = maxlen;
-       gdeftext = default_value;
-       strcpy(buf, readline(prompt));
-}
-
-
-// Exit from the program while displaying an error code
-void ctdlmigrate_exit(int cmdexit) {
-       printf("\n\n\033[3%dmExit code %d\033[0m\n", (cmdexit ? 1 : 2), cmdexit);
-       exit(cmdexit);
-}
-
-
-// Connect to a Citadel on a remote host using a TCP/IP socket
-static int tcp_connectsock(char *host, char *service) {
-       struct in6_addr serveraddr;
-       struct addrinfo hints;
-       struct addrinfo *res = NULL;
-       struct addrinfo *ai = NULL;
-       int rc = (-1);
-       int sock = (-1);
-
-       if ((host == NULL) || IsEmptyStr(host)) {
-               return(-1);
-       }
-       if ((service == NULL) || IsEmptyStr(service)) {
-               return(-1);
-       }
-
-       memset(&hints, 0x00, sizeof(hints));
-       hints.ai_flags = AI_NUMERICSERV;
-       hints.ai_family = AF_UNSPEC;
-       hints.ai_socktype = SOCK_STREAM;
-
-       // Handle numeric IPv4 and IPv6 addresses
-       rc = inet_pton(AF_INET, host, &serveraddr);
-       if (rc == 1) {                                  // dotted quad
-               hints.ai_family = AF_INET;
-               hints.ai_flags |= AI_NUMERICHOST;
-       }
-       else {
-               rc = inet_pton(AF_INET6, host, &serveraddr);
-               if (rc == 1) {                          // IPv6 address
-                       hints.ai_family = AF_INET6;
-                       hints.ai_flags |= AI_NUMERICHOST;
-               }
-       }
-
-       // Begin the connection process
-       rc = getaddrinfo(host, service, &hints, &res);
-       if (rc != 0) {
-               fprintf(stderr, "ctdlmigrate: %s\n", strerror(errno));
-               return (-1);
-       }
-
-       // Try all available addresses until we connect to one or until we run out.
-       for (ai = res; ai != NULL; ai = ai->ai_next) {
-               sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
-               if (sock < 0) {
-                       fprintf(stderr, "ctdlmigrate: %s\n", strerror(errno));
-                       return (-1);
-               }
-
-               rc = connect(sock, ai->ai_addr, ai->ai_addrlen);
-               if (rc >= 0) {
-                       return (sock);  // Connected!
-               }
-               else {
-                       fprintf(stderr, "ctdlmigrate: %s\n", strerror(errno));
-                       close(sock);    // Failed.  Close the socket to avoid fd leak!
-               }
-       }
-       return (-1);
-}
-
-
-// Connect to a Citadel on a remote host using a unix domaion socket
-int uds_connectsock(char *sockpath) {
-       int s;
-       struct sockaddr_un addr;
-
-       memset(&addr, 0, sizeof(addr));
-       addr.sun_family = AF_UNIX;
-       strcpy(addr.sun_path, sockpath);
-
-       s = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (s < 0) {
-               fprintf(stderr, "ctdlmigrate: Can't create socket: %s\n", strerror(errno));
-               return(-1);
-       }
-
-       if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               fprintf(stderr, "ctdlmigrate: can't connect: %s\n", strerror(errno));
-               close(s);
-               return(-1);
-       }
-
-       return s;
-}
-
-
-// input binary data from socket
-void serv_read(int serv_sock, char *buf, int bytes) {
-       int len = 0;
-       int rlen = 0;
-
-       while (len < bytes) {
-               rlen = read(serv_sock, &buf[len], bytes - len);
-               if (rlen < 1) {
-                       return;
-               }
-               len = len + rlen;
-       }
-}
-
-
-// send binary to server
-void serv_write(int serv_sock, char *buf, int nbytes) {
-       int bytes_written = 0;
-       int retval;
-       while (bytes_written < nbytes) {
-               retval = write(serv_sock, &buf[bytes_written], nbytes - bytes_written);
-               if (retval < 1) {
-                       return;
-               }
-               bytes_written = bytes_written + retval;
-       }
-}
-
-
-// input string from socket - implemented in terms of serv_read()
-void serv_gets(int serv_sock, char *buf) {
-       int i;
-
-       // Read one character at a time.
-       for (i = 0;; i++) {
-               serv_read(serv_sock, &buf[i], 1);
-               if (buf[i] == '\n' || i == (SIZ-1))
-                       break;
-       }
-
-       // If we got a long line, discard characters until the newline.
-       if (i == (SIZ-1)) {
-               while (buf[i] != '\n') {
-                       serv_read(serv_sock, &buf[i], 1);
-               }
-       }
-
-       // Strip all trailing nonprintables (crlf)
-       buf[i] = 0;
-}
-
-
-// send line to server - implemented in terms of serv_write()
-void serv_puts(int serv_sock, char *buf) {
-       serv_write(serv_sock, buf, strlen(buf));
-       serv_write(serv_sock, "\n", 1);
-}
-
-
-// send formatted printable data to the server
-void serv_printf(int serv_sock, const char *format, ...) {   
-       va_list arg_ptr;   
-       char buf[1024];
-   
-       va_start(arg_ptr, format);   
-       if (vsnprintf(buf, sizeof buf, format, arg_ptr) == -1)
-               buf[sizeof buf - 2] = '\n';
-       serv_write(serv_sock, buf, strlen(buf)); 
-       va_end(arg_ptr);
-}
-
-
-// You know what main() does.  If you don't, you shouldn't be trying to understand this program.
-int main(int argc, char *argv[]) {
-       char ctdldir[PATH_MAX]=CTDLDIR;
-       char yesno[2];
-       int cmdexit = 0;                                // when something fails, set cmdexit to nonzero, and skip to the end
-       char buf[PATH_MAX];
-
-       char remote_user[128];
-       char remote_host[128];
-       char remote_pass[128];
-       char *remote_port = "504";
-
-       int linecount = 0;
-       int a;
-       int remote_server_socket = (-1);
-       int local_admin_socket = (-1);
-       int progress = 0;
-
-       // Parse command line
-       while ((a = getopt(argc, argv, "h:")) != EOF) {
-               switch (a) {
-               case 'h':
-                       strcpy(ctdldir, optarg);
-                       break;
-               default:
-                       fprintf(stderr, "ctdlmigrate: usage: ctdlmigrate [-h server_dir]\n");
-                       return(1);
-               }
-       }
-
-       if (chdir(ctdldir) != 0) {
-               fprintf(stderr, "ctdlmigrate: %s: %s\n", ctdldir, strerror(errno));
-               exit(errno);
-       }
-
-       signal(SIGINT, ctdlmigrate_exit);
-       signal(SIGQUIT, ctdlmigrate_exit);
-       signal(SIGTERM, ctdlmigrate_exit);
-       signal(SIGSEGV, ctdlmigrate_exit);
-       signal(SIGHUP, ctdlmigrate_exit);
-       signal(SIGPIPE, ctdlmigrate_exit);
-
-       printf( "\033[2J\033[H\n"
-               "          \033[32m╔═══════════════════════════════════════════════╗\n"
-               "          ║                                               ║\n"
-               "          ║    \033[33mCitadel over-the-wire migration utility    \033[32m║\n"
-               "          ║                                               ║\n"
-               "          ╚═══════════════════════════════════════════════╝\033[0m\n"
-               "\n"
-               "This utility is designed to migrate your Citadel installation\n"
-               "to a new host system via a network connection, without disturbing\n"
-               "the source system.  The target may be a different CPU architecture\n"
-               "and/or operating system.  The source system should be running\n"
-               "Citadel version \033[33m%d\033[0m or newer, and the target system should be running\n"
-               "either the same version or a newer version.\n"
-               "\n"
-               "You must run this utility on the TARGET SYSTEM.  Any existing data\n"
-               "on this system will be ERASED.  Your target system will be on this\n"
-               "host in %s.\n"
-               "\n",
-               EXPORT_REV_MIN, ctdldir
-       );
-
-       getz(yesno, 1, NULL, "Do you wish to continue? ");
-       puts(yesno);
-       if (tolower(yesno[0]) != 'y') {
-               cmdexit = 101;
-       }
-
-       if (!cmdexit) {
-               printf( "\033[2J\033[H\n"
-                       "\033[32m╔═══════════════════════════════════════════════╗\n"
-                       "║                                               ║\n"
-                       "║       \033[33mValidate source and target systems\033[32m      ║\n"
-                       "║                                               ║\n"
-                       "╚═══════════════════════════════════════════════╝\033[0m\n"
-                       "\n\n");
-       
-               printf("First we must validate that the local target system is running\n");
-               printf("and ready to receive data.\n");
-               printf("Checking connectivity to Citadel in %s...\n", ctdldir);
-               local_admin_socket = uds_connectsock("citadel-admin.socket");
-               if (local_admin_socket < 0) {
-                       cmdexit = 102;
-               }
-       }
-
-       if (!cmdexit) {
-               serv_gets(local_admin_socket, buf);
-               puts(buf);
-               if (buf[0] != '2') {
-                       cmdexit = 103;
-               }
-       }
-
-       if (!cmdexit) {
-               serv_puts(local_admin_socket, "ECHO Connection to Citadel Server succeeded.");
-               serv_gets(local_admin_socket, buf);
-               puts(buf);
-               if (buf[0] != '2') {
-                       cmdexit = 104;
-               }
-       }
-
-       if (!cmdexit) {
-               printf("\n");
-               printf("OK, this side is ready to go.  Now we must connect to the source system.\n\n");
-
-               getz(remote_host, sizeof remote_host, NULL,     "Enter the name or IP address of the source system: ");
-               getz(remote_user, sizeof remote_user, "admin",  "  Enter the user name of an administrator account: ");
-               getz(remote_pass, sizeof remote_pass, NULL,     "              Enter the password for this account: ");
-
-               remote_server_socket = tcp_connectsock(remote_host, remote_port);
-               if (remote_server_socket < 0) {
-                       cmdexit = 105;
-               }
-       }
-
-       if (!cmdexit) {
-               serv_gets(remote_server_socket, buf);
-               puts(buf);
-               if (buf[0] != '2') {
-                       cmdexit = 106;
-               }
-       }
-
-       if (!cmdexit) {
-               serv_printf(remote_server_socket, "USER %s\n", remote_user);
-               serv_gets(remote_server_socket, buf);
-               puts(buf);
-               if (buf[0] != '3') {
-                       cmdexit = 107;
-               }
-       }
-
-       if (!cmdexit) {
-               serv_printf(remote_server_socket, "PASS %s\n", remote_pass);
-               serv_gets(remote_server_socket, buf);
-               puts(buf);
-               if (buf[0] != '2') {
-                       cmdexit = 108;
-               }
-       }
-
-       if (!cmdexit) {
-               printf( "\033[2J\033[H\n"
-                       "\033[32m╔═══════════════════════════════════════════════════════════════════╗\n"
-                       "║                                                                   ║\n"
-                       "║ \033[33mMigrating from: %-50s\033[32m║\n"
-                       "║                                                                   ║\n"
-                       "╠═══════════════════════════════════════════════════════════════════╣\n"
-                       "║                                                                   ║\n"
-                       "║ Lines received: 0                           Percent complete: 0   ║\n"
-                       "║                                                                   ║\n"
-                       "╚═══════════════════════════════════════════════════════════════════╝\033[0m\n"
-                       "\n", remote_host
-               );
-       }
-
-       if (!cmdexit) {
-               serv_puts(remote_server_socket, "MIGR export");
-               serv_gets(remote_server_socket, buf);
-               if (buf[0] != '1') {
-                       printf("\n\033[31m%s\033[0m\n", buf);
-                       cmdexit = 109;
-               }
-       }
-
-       if (!cmdexit) {
-               serv_puts(local_admin_socket, "MIGR import");
-               serv_gets(local_admin_socket, buf);
-               if (buf[0] != '4') {
-                       printf("\n\033[31m%s\033[0m\n", buf);
-                       cmdexit = 110;
-               }
-       }
-
-       if (!cmdexit) {
-               char *ptr;
-               time_t last_update = time(NULL);
-
-               while (serv_gets(remote_server_socket, buf), strcmp(buf, "000")) {
-                       ptr = strchr(buf, '\n');
-                       if (ptr) *ptr = 0;      // remove the newline character
-                       ++linecount;
-                       if (!strncasecmp(buf, "<progress>", 10)) {
-                               progress = atoi(&buf[10]);
-                               printf("\033[8;65H\033[33m%d\033[0m\033[12;0H\n", progress);
-                       }
-                       if (time(NULL) != last_update) {
-                               last_update = time(NULL);
-                               printf("\033[8;19H\033[33m%d\033[0m\033[12;0H\n", linecount);
-                       }
-                       serv_puts(local_admin_socket, buf);
-               }
-       
-               serv_puts(local_admin_socket, "000");
-       }
-
-       if ( (cmdexit == 0) && (progress < 100) ) {
-               printf("\033[31mERROR: source stream ended before 100 percent of data was received.\033[0m\n");
-               cmdexit = 111;
-       }
-
-       if (!cmdexit) {
-               printf("\033[36mMigration is complete.  Restarting the target server.\033[0m\n");
-               serv_puts(local_admin_socket, "DOWN 1");
-               serv_gets(local_admin_socket, buf);
-               puts(buf);
-               printf("\033[36mIt is recommended that you shut down the source server now.\033[0m\n");
-               printf("\033[36mRemember to copy over your SSL keys and file libraries if appropriate.\033[0m\n");
-       }
-
-       close(remote_server_socket);
-       close(local_admin_socket);
-       ctdlmigrate_exit(cmdexit);
-}