From eaa5fd8ad0d576c8e34ec04083e5462119f85e35 Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Mon, 17 Jul 2023 18:42:29 -0900 Subject: [PATCH] Removed serv_migrate.c and ctdlmigrate. They are replaced by ctdldump and ctdlload. --- citadel/Makefile | 2 +- citadel/server/modules/migrate/serv_migrate.c | 1080 ----------------- citadel/server/modules_init.c | 1 - citadel/utils/ctdlmigrate.c | 453 ------- 4 files changed, 1 insertion(+), 1535 deletions(-) delete mode 100644 citadel/server/modules/migrate/serv_migrate.c delete mode 100644 citadel/utils/ctdlmigrate.c diff --git a/citadel/Makefile b/citadel/Makefile index edd3d0282..87c310158 100644 --- a/citadel/Makefile +++ b/citadel/Makefile @@ -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 index 3a58bac63..000000000 --- a/citadel/server/modules/migrate/serv_migrate.c +++ /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 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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(""")); - } - else if (*c == '\'') { - client_write(HKEY("'")); - } - else if (*c == '<') { - client_write(HKEY("<")); - } - else if (*c == '>') { - client_write(HKEY(">")); - } - else if (*c == '&') { - client_write(HKEY("&")); - } - 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("\n")); - cprintf("%d\n", u.version); - cprintf("%ld\n", (long)u.uid); - client_write(HKEY("")); xml_strout(u.password); client_write(HKEY("\n")); - cprintf("%u\n", u.flags); - cprintf("%d\n", u.axlevel); - cprintf("%ld\n", u.usernum); - cprintf("%ld\n", (long)u.lastcall); - cprintf("%d\n", u.USuserpurge); - client_write(HKEY("")); xml_strout(u.fullname); client_write(HKEY("\n")); - cprintf("%ld\n", u.msgnum_bio); - cprintf("%ld\n", u.msgnum_pic); - cprintf("%s\n", u.emailaddrs); - cprintf("%ld\n", u.msgnum_inboxrules); - cprintf("%ld\n", u.lastproc_inboxrules); - client_write(HKEY("\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("\n")); - client_write(HKEY("")); - xml_strout(buf->QRname); - client_write(HKEY("\n")); - client_write(HKEY("")); - xml_strout(buf->QRpasswd); - client_write(HKEY("\n")); - cprintf("%ld\n", buf->QRroomaide); - cprintf("%ld\n", buf->QRhighest); - cprintf("%ld\n", (long)buf->QRgen); - cprintf("%u\n", buf->QRflags); - if (buf->QRflags & QR_DIRECTORY) { - client_write(HKEY("")); - xml_strout(buf->QRdirname); - client_write(HKEY("\n")); - } - cprintf("%d\n", buf->QRfloor); - cprintf("%ld\n", (long)buf->QRmtime); - cprintf("%d\n", buf->QRep.expire_mode); - cprintf("%d\n", buf->QRep.expire_value); - cprintf("%ld\n", buf->QRnumber); - cprintf("%d\n", buf->QRorder); - cprintf("%u\n", buf->QRflags2); - cprintf("%d\n", buf->QRdefaultview); - cprintf("%ld\n", buf->msgnum_info); - cprintf("%ld\n", buf->msgnum_pic); - client_write(HKEY("\n")); - - // message list goes inside this tag - CtdlGetRoom(&CC->room, buf->QRname); - client_write(HKEY("")); - client_write(HKEY("")); - xml_strout(buf->QRname); // buf->QRname rather than CC->room.QRname to guarantee consistency - client_write(HKEY("\n")); - client_write(HKEY("\n")); - CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, migr_export_room_msg, NULL); - client_write(HKEY("\n")); - client_write(HKEY("\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("\n")); - cprintf("%d\n", i); - CtdlGetFloor(&qfbuf, i); - buf = &qfbuf; - cprintf("%u\n", buf->f_flags); - client_write(HKEY("")); xml_strout(buf->f_name); client_write(HKEY("\n")); - cprintf("%d\n", buf->f_ref_count); - cprintf("%d\n", buf->f_ep.expire_mode); - cprintf("%d\n", buf->f_ep.expire_value); - client_write(HKEY("\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("\n")); - cprintf("%ld\n", vbuf.v_roomnum); - cprintf("%ld\n", vbuf.v_roomgen); - cprintf("%ld\n", vbuf.v_usernum); - - client_write(HKEY("")); - 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("")); - - if ( (!IsEmptyStr(vbuf.v_answered)) && (is_sequence_set(vbuf.v_answered)) ) { - client_write(HKEY("")); - xml_strout(vbuf.v_answered); - client_write(HKEY("\n")); - } - - cprintf("%u\n", vbuf.v_flags); - cprintf("%d\n", vbuf.v_view); - client_write(HKEY("\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("\n")); - GetMetaData(&smi, msgnum); - cprintf("%ld\n", msgnum); - cprintf("%d\n", smi.meta_refcount); - cprintf("%ld\n", smi.meta_rfc822_length); - client_write(HKEY("")); xml_strout(smi.meta_content_type); client_write(HKEY("\n")); - - client_write(HKEY("")); - 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("\n")); - client_write(HKEY("\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("", 2); - xml_strout(value); - client_write("\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("%d\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("\n")); - client_write(HKEY("\n")); - cprintf("%d\n", REV_LEVEL); - cprintf("%d\n", 0); - - // export the configuration database - migr_export_configs(); - cprintf("%d\n", 2); - - if (Ctx->kill_me == 0) migr_export_users(); - cprintf("%d\n", 7); - cprintf("%d\n", 12); - if (Ctx->kill_me == 0) migr_export_rooms(); - cprintf("%d\n", 17); - if (Ctx->kill_me == 0) migr_export_floors(); - cprintf("%d\n", 18); - if (Ctx->kill_me == 0) migr_export_visits(); - cprintf("%d\n", 25); - if (Ctx->kill_me == 0) migr_export_messages(); - cprintf("%d\n", 100); - client_write(HKEY("\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 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 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"; -} diff --git a/citadel/server/modules_init.c b/citadel/server/modules_init.c index a79f6d326..c405c311a 100644 --- a/citadel/server/modules_init.c +++ b/citadel/server/modules_init.c @@ -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 index 6b1af0297..000000000 --- a/citadel/utils/ctdlmigrate.c +++ /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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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, "", 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); -} -- 2.30.2