time_t QRgen; /* Generation number of room */
unsigned QRflags; /* See flag values below */
char QRdirname[15]; /* Directory name, if applicable */
- long QRinfo; /* Info file update relative to msgs*/
+ long msgnum_info; /* msgnum of room banner (info file)*/
char QRfloor; /* Which floor this room is on */
time_t QRmtime; /* Date/time of last post */
struct ExpirePolicy QRep; /* Message expiration policy */
char QRorder; /* Sort key for room listing order */
unsigned QRflags2; /* Additional flags */
int QRdefaultview; /* How to display the contents */
+ long msgnum_pic; /* msgnum of room picture or icon */
};
/* Private rooms are always flagged with QR_PRIVATE. If neither QR_PASSWORDED
/* now update the room index so people will see our new info */
CtdlGetRoomLock(&CCC->room, CCC->room.QRname); /* lock so no one steps on us */
- CCC->room.QRinfo = CCC->room.QRhighest + 1L;
CtdlPutRoomLock(&CCC->room);
}
xml_strout(buf->QRdirname);
client_write(HKEY("</QRdirname>\n"));
}
- cprintf("<QRinfo>%ld</QRinfo>\n", buf->QRinfo);
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("<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 */
int migr_roomrecord(void *data, const char *el)
{
- if (!strcasecmp(el, "QRname")) safestrncpy(qrbuf.QRname, ChrPtr(migr_chardata), sizeof qrbuf.QRname);
+ 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, "QRinfo")) qrbuf.QRinfo = atol(ChrPtr(migr_chardata));
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, "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;
}
cprintf("messages|%s\n", ctdl_message_dir);
cprintf("keys|%s\n", ctdl_key_dir);
cprintf("images|%s\n", ctdl_image_dir);
- cprintf("info|%s\n", ctdl_info_dir);
cprintf("000\n");
}
/*
- * Transparently handle the upgrading of server data formats.
+ * Transparently handle the upgrading of server data formats. If we see
+ * an existing version number of our database, we can make some intelligent
+ * guesses about what kind of data format changes need to be applied, and
+ * we apply them transparently.
*
* Copyright (c) 1987-2016 by the citadel.org team
*
}
+
+/*
+ * Per-room callback function for ingest_old_roominfo_and_roompic_files()
+ *
+ * This is the second pass, where we process the list of rooms with info or pic files.
+ */
+void iorarf_oneroom(char *roomname, char *infofile, char *picfile)
+{
+ FILE *fp;
+ long data_length;
+ char *unencoded_data;
+ char *encoded_data;
+ long info_msgnum = 0;
+ long pic_msgnum = 0;
+ char subject[SIZ];
+
+ syslog(LOG_DEBUG, "iorarf_oneroom( %s , %s , %s )", roomname, infofile, picfile);
+
+ // Test for the presence of a legacy "room info file"
+ if (!IsEmptyStr(infofile)) {
+ fp = fopen(infofile, "r");
+ }
+ else {
+ fp = NULL;
+ }
+ if (fp) {
+ fseek(fp, 0, SEEK_END);
+ data_length = ftell(fp);
+
+ if (data_length >= 1) {
+ rewind(fp);
+ unencoded_data = malloc(data_length);
+ if (unencoded_data) {
+ fread(unencoded_data, data_length, 1, fp);
+ encoded_data = malloc((data_length * 2) + 100);
+ if (encoded_data) {
+ sprintf(encoded_data, "Content-type: text/plain\nContent-transfer-encoding: base64\n\n");
+ CtdlEncodeBase64(&encoded_data[strlen(encoded_data)], unencoded_data, data_length, 1);
+ snprintf(subject, sizeof subject, "Imported room banner for %s", roomname);
+ info_msgnum = quickie_message("Citadel", NULL, NULL, SYSCONFIGROOM, encoded_data, FMT_RFC822, subject);
+ free(encoded_data);
+ }
+ free(unencoded_data);
+ }
+ }
+ fclose(fp);
+ // unlink(filename);
+ }
+
+ // Test for the presence of a legacy "room picture file" and import it.
+ if (!IsEmptyStr(picfile)) {
+ fp = fopen(picfile, "r");
+ }
+ else {
+ fp = NULL;
+ }
+ if (fp) {
+ fseek(fp, 0, SEEK_END);
+ data_length = ftell(fp);
+
+ if (data_length >= 1) {
+ rewind(fp);
+ unencoded_data = malloc(data_length);
+ if (unencoded_data) {
+ fread(unencoded_data, data_length, 1, fp);
+ encoded_data = malloc((data_length * 2) + 100);
+ if (encoded_data) {
+ sprintf(encoded_data, "Content-type: image/gif\nContent-transfer-encoding: base64\n\n");
+ CtdlEncodeBase64(&encoded_data[strlen(encoded_data)], unencoded_data, data_length, 1);
+ snprintf(subject, sizeof subject, "Imported room icon for %s", roomname);
+ pic_msgnum = quickie_message("Citadel", NULL, NULL, SYSCONFIGROOM, encoded_data, FMT_RFC822, subject);
+ free(encoded_data);
+ }
+ free(unencoded_data);
+ }
+ }
+ fclose(fp);
+ // unlink(filename);
+ }
+
+ // Now we have the message numbers of our new banner and icon. Record them in the room record.
+ // NOTE: we are not deleting the old msgnum_info because that position in the record was previously
+ // a pointer to the highest message number which existed in the room when the info file was saved,
+ // and we don't want to delete messages that are not *actually* old banners.
+ struct ctdlroom qrbuf;
+ if (CtdlGetRoomLock(&qrbuf, roomname) == 0) {
+ qrbuf.msgnum_info = info_msgnum;
+ qrbuf.msgnum_pic = pic_msgnum;
+ CtdlPutRoomLock(&qrbuf);
+ }
+
+}
+
+
+
+struct iorarf_list {
+ struct iorarf_list *next;
+ char name[ROOMNAMELEN];
+ char info[PATH_MAX];
+ char pic[PATH_MAX];
+};
+
+
+/*
+ * Per-room callback function for ingest_old_roominfo_and_roompic_files()
+ *
+ * This is the first pass, where the list of qualifying rooms is gathered.
+ */
+void iorarf_backend(struct ctdlroom *qrbuf, void *data)
+{
+ FILE *fp;
+ struct iorarf_list **iorarf_list = (struct iorarf_list **)data;
+
+ struct iorarf_list *i = malloc(sizeof(struct iorarf_list));
+ i->next = *iorarf_list;
+ strcpy(i->name, qrbuf->QRname);
+ strcpy(i->info, "");
+ strcpy(i->pic, "");
+
+ // Test for the presence of a legacy "room info file"
+ assoc_file_name(i->info, sizeof i->info, qrbuf, ctdl_info_dir);
+ fp = fopen(i->info, "r");
+ if (fp) {
+ fclose(fp);
+ }
+ else {
+ i->info[0] = 0;
+ }
+
+ // Test for the presence of a legacy "room picture file"
+ assoc_file_name(i->pic, sizeof i->pic, qrbuf, ctdl_image_dir);
+ fp = fopen(i->pic, "r");
+ if (fp) {
+ fclose(fp);
+ }
+ else {
+ i->pic[0] = 0;
+ }
+
+ if ( (!IsEmptyStr(i->info)) || (!IsEmptyStr(i->pic)) ) {
+ *iorarf_list = i;
+ }
+ else {
+ free(i);
+ }
+}
+
+
+/*
+ * Prior to Citadel Server version 902, room info and pictures (which comprise the
+ * displayed banner for each room) were stored in the filesystem. If we are upgrading
+ * from version >000 to version >=902, ingest those files into the database.
+ */
+void ingest_old_roominfo_and_roompic_files(void)
+{
+ struct iorarf_list *il = NULL;
+
+ CtdlForEachRoom(iorarf_backend, &il);
+
+ struct iorarf_list *p;
+ while (il) {
+ iorarf_oneroom(il->name, il->info, il->pic);
+ p = il->next;
+ free(il);
+ il = p;
+ }
+
+}
+
+
/*
* Perform any upgrades that can be done automatically based on our knowledge of the previous
* version of Citadel server that was running here.
}
}
+ if ((CtdlGetConfigInt("MM_hosted_upgrade_level") > 000) && (CtdlGetConfigInt("MM_hosted_upgrade_level") < 902)) {
+ ingest_old_roominfo_and_roompic_files();
+ }
+
CtdlSetConfigInt("MM_hosted_upgrade_level", REV_LEVEL);
/*
CTDL_MODULE_UPGRADE(upgrade)
{
check_server_upgrades();
+ ingest_old_roominfo_and_roompic_files(); // FIXME remove this line, it's proper above!!!!
/* return our module id for the Log */
return "upgrade";
/* Check for new mail */
newmailcount = NewMailCount();
- /* set info to 1 if the user needs to read the room's info file */
- if (CCC->room.QRinfo > vbuf.v_lastseen) {
+ /* Set info to 1 if the room banner is new since our last visit.
+ * Some clients only want to display it when it changes.
+ */
+ if (CCC->room.msgnum_info > vbuf.v_lastseen) {
info = 1;
}
int create_run_directories(long UID, long GID)
{
- int rv;
-
- rv = create_dir(ctdl_info_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
- if (rv != -1)
- rv = create_dir(ctdl_message_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
- if (rv != -1)
- rv = create_dir(ctdl_hlp_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
- if (rv != -1)
- rv = create_dir(ctdl_image_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
- if (rv != -1)
- rv = create_dir(ctdl_bb_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
- if (rv != -1)
- rv = create_dir(ctdl_file_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
- if (rv != -1)
- rv = create_dir(ctdl_spool_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
- if (rv != -1)
- rv = create_dir(ctdl_netout_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
- if (rv != -1)
- rv = create_dir(ctdl_netin_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
- if (rv != -1)
- rv = create_dir(ctdl_netdigest_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
- if (rv != -1)
- rv = create_dir(ctdl_nettmp_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
- if (rv != -1)
- rv = create_dir(ctdl_key_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
- if (rv != -1)
- rv = create_dir(ctdl_run_dir , S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH, UID, GID);
+ int rv = 0;
+ rv += create_dir(ctdl_message_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
+ rv += create_dir(ctdl_hlp_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
+ rv += create_dir(ctdl_image_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
+ rv += create_dir(ctdl_bb_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
+ rv += create_dir(ctdl_file_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
+ rv += create_dir(ctdl_spool_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
+ rv += create_dir(ctdl_netout_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
+ rv += create_dir(ctdl_netin_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
+ rv += create_dir(ctdl_netdigest_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
+ rv += create_dir(ctdl_nettmp_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
+ rv += create_dir(ctdl_key_dir , S_IRUSR|S_IWUSR|S_IXUSR, UID, -1);
+ rv += create_dir(ctdl_run_dir , S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH, UID, GID);
return rv;
}
snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/",
socket_path, remote_user, remote_host, &buf[7], ctdl_image_dir);
}
- else if (!strncasecmp(buf, "info|", 5)) {
- snprintf(cmd, sizeof cmd, "rsync -va --rsh='ssh -S %s' %s@%s:%s/ %s/",
- socket_path, remote_user, remote_host, &buf[5], ctdl_info_dir);
- }
else {
strcpy(cmd, "false"); /* cheap and sleazy way to throw an error */
}