/* * Initialize the SMTP outbound queue */ void smtp_init_spoolout(void) { struct ctdlroom qrbuf; /* * Create the room. This will silently fail if the room already * exists, and that's perfectly ok, because we want it to exist. */ CtdlCreateRoom(SMTP_SPOOLOUT_ROOM, 3, "", 0, 1, 0, VIEW_QUEUE); /* * Make sure it's set to be a "system room" so it doesn't show up * in the <K>nown rooms list for Aides. */ if (CtdlGetRoomLock(&qrbuf, SMTP_SPOOLOUT_ROOM) == 0) { qrbuf.QRflags2 |= QR2_SYSTEM; CtdlPutRoomLock(&qrbuf); } }
/* * Get or set global configuration options * * IF YOU ADD OR CHANGE FIELDS HERE, YOU *MUST* DOCUMENT YOUR CHANGES AT: * http://www.citadel.org/doku.php?id=documentation:applicationprotocol * */ void cmd_conf(char *argbuf) { char cmd[16]; char buf[256]; int a; char *confptr; char confname[128]; if (CtdlAccessCheck(ac_aide)) return; extract_token(cmd, argbuf, 0, '|', sizeof cmd); if (!strcasecmp(cmd, "GET")) { cprintf("%d Configuration...\n", LISTING_FOLLOWS); cprintf("%s\n", config.c_nodename); cprintf("%s\n", config.c_fqdn); cprintf("%s\n", config.c_humannode); cprintf("%s\n", config.c_phonenum); cprintf("%d\n", config.c_creataide); cprintf("%d\n", config.c_sleeping); cprintf("%d\n", config.c_initax); cprintf("%d\n", config.c_regiscall); cprintf("%d\n", config.c_twitdetect); cprintf("%s\n", config.c_twitroom); cprintf("%s\n", config.c_moreprompt); cprintf("%d\n", config.c_restrict); cprintf("%s\n", config.c_site_location); cprintf("%s\n", config.c_sysadm); cprintf("%d\n", config.c_maxsessions); cprintf("xxx\n"); /* placeholder -- field no longer in use */ cprintf("%d\n", config.c_userpurge); cprintf("%d\n", config.c_roompurge); cprintf("%s\n", config.c_logpages); cprintf("%d\n", config.c_createax); cprintf("%ld\n", config.c_maxmsglen); cprintf("%d\n", config.c_min_workers); cprintf("%d\n", config.c_max_workers); cprintf("%d\n", config.c_pop3_port); cprintf("%d\n", config.c_smtp_port); cprintf("%d\n", config.c_rfc822_strict_from); cprintf("%d\n", config.c_aide_zap); cprintf("%d\n", config.c_imap_port); cprintf("%ld\n", config.c_net_freq); cprintf("%d\n", config.c_disable_newu); cprintf("1\n"); /* niu */ cprintf("%d\n", config.c_purge_hour); #ifdef HAVE_LDAP cprintf("%s\n", config.c_ldap_host); cprintf("%d\n", config.c_ldap_port); cprintf("%s\n", config.c_ldap_base_dn); cprintf("%s\n", config.c_ldap_bind_dn); cprintf("%s\n", config.c_ldap_bind_pw); #else cprintf("\n"); cprintf("0\n"); cprintf("\n"); cprintf("\n"); cprintf("\n"); #endif cprintf("%s\n", config.c_ip_addr); cprintf("%d\n", config.c_msa_port); cprintf("%d\n", config.c_imaps_port); cprintf("%d\n", config.c_pop3s_port); cprintf("%d\n", config.c_smtps_port); cprintf("%d\n", config.c_enable_fulltext); cprintf("%d\n", config.c_auto_cull); cprintf("1\n"); cprintf("%d\n", config.c_allow_spoofing); cprintf("%d\n", config.c_journal_email); cprintf("%d\n", config.c_journal_pubmsgs); cprintf("%s\n", config.c_journal_dest); cprintf("%s\n", config.c_default_cal_zone); cprintf("%d\n", config.c_pftcpdict_port); cprintf("%d\n", config.c_managesieve_port); cprintf("%d\n", config.c_auth_mode); cprintf("%s\n", config.c_funambol_host); cprintf("%d\n", config.c_funambol_port); cprintf("%s\n", config.c_funambol_source); cprintf("%s\n", config.c_funambol_auth); cprintf("%d\n", config.c_rbl_at_greeting); cprintf("%s\n", config.c_master_user); cprintf("%s\n", config.c_master_pass); cprintf("%s\n", config.c_pager_program); cprintf("%d\n", config.c_imap_keep_from); cprintf("%d\n", config.c_xmpp_c2s_port); cprintf("%d\n", config.c_xmpp_s2s_port); cprintf("%ld\n", config.c_pop3_fetch); cprintf("%ld\n", config.c_pop3_fastest); cprintf("%d\n", config.c_spam_flag_only); cprintf("%d\n", config.c_guest_logins); cprintf("%d\n", config.c_port_number); cprintf("%d\n", config.c_ctdluid); cprintf("%d\n", config.c_nntp_port); cprintf("%d\n", config.c_nntps_port); cprintf("000\n"); } else if (!strcasecmp(cmd, "SET")) { unbuffer_output(); cprintf("%d Send configuration...\n", SEND_LISTING); a = 0; while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) { switch (a) { case 0: configlen.c_nodename = safestrncpy(config.c_nodename, buf, sizeof config.c_nodename); break; case 1: configlen.c_fqdn = safestrncpy(config.c_fqdn, buf, sizeof config.c_fqdn); break; case 2: configlen.c_humannode = safestrncpy(config.c_humannode, buf, sizeof config.c_humannode); break; case 3: configlen.c_phonenum = safestrncpy(config.c_phonenum, buf, sizeof config.c_phonenum); break; case 4: config.c_creataide = atoi(buf); break; case 5: config.c_sleeping = atoi(buf); break; case 6: config.c_initax = atoi(buf); if (config.c_initax < 1) config.c_initax = 1; if (config.c_initax > 6) config.c_initax = 6; break; case 7: config.c_regiscall = atoi(buf); if (config.c_regiscall != 0) config.c_regiscall = 1; break; case 8: config.c_twitdetect = atoi(buf); if (config.c_twitdetect != 0) config.c_twitdetect = 1; break; case 9: configlen.c_twitroom = safestrncpy(config.c_twitroom, buf, sizeof config.c_twitroom); break; case 10: configlen.c_moreprompt = safestrncpy(config.c_moreprompt, buf, sizeof config.c_moreprompt); break; case 11: config.c_restrict = atoi(buf); if (config.c_restrict != 0) config.c_restrict = 1; break; case 12: configlen.c_site_location = safestrncpy( config.c_site_location, buf, sizeof config.c_site_location); break; case 13: configlen.c_sysadm = safestrncpy(config.c_sysadm, buf, sizeof config.c_sysadm); break; case 14: config.c_maxsessions = atoi(buf); if (config.c_maxsessions < 0) config.c_maxsessions = 0; break; case 15: /* placeholder -- field no longer in use */ break; case 16: config.c_userpurge = atoi(buf); break; case 17: config.c_roompurge = atoi(buf); break; case 18: configlen.c_logpages = safestrncpy(config.c_logpages, buf, sizeof config.c_logpages); break; case 19: config.c_createax = atoi(buf); if (config.c_createax < 1) config.c_createax = 1; if (config.c_createax > 6) config.c_createax = 6; break; case 20: if (atoi(buf) >= 8192) config.c_maxmsglen = atoi(buf); break; case 21: if (atoi(buf) >= 2) config.c_min_workers = atoi(buf); case 22: if (atoi(buf) >= config.c_min_workers) config.c_max_workers = atoi(buf); case 23: config.c_pop3_port = atoi(buf); break; case 24: config.c_smtp_port = atoi(buf); break; case 25: config.c_rfc822_strict_from = atoi(buf); break; case 26: config.c_aide_zap = atoi(buf); if (config.c_aide_zap != 0) config.c_aide_zap = 1; break; case 27: config.c_imap_port = atoi(buf); break; case 28: config.c_net_freq = atol(buf); break; case 29: config.c_disable_newu = atoi(buf); if (config.c_disable_newu != 0) config.c_disable_newu = 1; break; case 30: /* niu */ break; case 31: if ((config.c_purge_hour >= 0) && (config.c_purge_hour <= 23)) { config.c_purge_hour = atoi(buf); } break; #ifdef HAVE_LDAP case 32: configlen.c_ldap_host = safestrncpy(config.c_ldap_host, buf, sizeof config.c_ldap_host); break; case 33: config.c_ldap_port = atoi(buf); break; case 34: configlen.c_ldap_base_dn = safestrncpy(config.c_ldap_base_dn, buf, sizeof config.c_ldap_base_dn); break; case 35: configlen.c_ldap_bind_dn = safestrncpy(config.c_ldap_bind_dn, buf, sizeof config.c_ldap_bind_dn); break; case 36: configlen.c_ldap_bind_pw = safestrncpy(config.c_ldap_bind_pw, buf, sizeof config.c_ldap_bind_pw); break; #endif case 37: configlen.c_ip_addr = safestrncpy(config.c_ip_addr, buf, sizeof config.c_ip_addr); case 38: config.c_msa_port = atoi(buf); break; case 39: config.c_imaps_port = atoi(buf); break; case 40: config.c_pop3s_port = atoi(buf); break; case 41: config.c_smtps_port = atoi(buf); break; case 42: config.c_enable_fulltext = atoi(buf); break; case 43: config.c_auto_cull = atoi(buf); break; case 44: /* niu */ break; case 45: config.c_allow_spoofing = atoi(buf); break; case 46: config.c_journal_email = atoi(buf); break; case 47: config.c_journal_pubmsgs = atoi(buf); break; case 48: configlen.c_journal_dest = safestrncpy(config.c_journal_dest, buf, sizeof config.c_journal_dest); case 49: configlen.c_default_cal_zone = safestrncpy( config.c_default_cal_zone, buf, sizeof config.c_default_cal_zone); break; case 50: config.c_pftcpdict_port = atoi(buf); break; case 51: config.c_managesieve_port = atoi(buf); break; case 52: config.c_auth_mode = atoi(buf); case 53: configlen.c_funambol_host = safestrncpy( config.c_funambol_host, buf, sizeof config.c_funambol_host); break; case 54: config.c_funambol_port = atoi(buf); break; case 55: configlen.c_funambol_source = safestrncpy( config.c_funambol_source, buf, sizeof config.c_funambol_source); break; case 56: configlen.c_funambol_auth = safestrncpy( config.c_funambol_auth, buf, sizeof config.c_funambol_auth); break; case 57: config.c_rbl_at_greeting = atoi(buf); break; case 58: configlen.c_master_user = safestrncpy( config.c_master_user, buf, sizeof config.c_master_user); break; case 59: configlen.c_master_pass = safestrncpy( config.c_master_pass, buf, sizeof config.c_master_pass); break; case 60: configlen.c_pager_program = safestrncpy( config.c_pager_program, buf, sizeof config.c_pager_program); break; case 61: config.c_imap_keep_from = atoi(buf); break; case 62: config.c_xmpp_c2s_port = atoi(buf); break; case 63: config.c_xmpp_s2s_port = atoi(buf); break; case 64: config.c_pop3_fetch = atol(buf); break; case 65: config.c_pop3_fastest = atol(buf); break; case 66: config.c_spam_flag_only = atoi(buf); break; case 67: config.c_guest_logins = atoi(buf); break; case 68: config.c_port_number = atoi(buf); break; case 69: config.c_ctdluid = atoi(buf); break; case 70: config.c_nntp_port = atoi(buf); break; case 71: config.c_nntps_port = atoi(buf); break; } ++a; } put_config(); snprintf(buf, sizeof buf, "The global system configuration has been edited by %s.\n", (CC->logged_in ? CC->curr_user : "******") ); CtdlAideMessage(buf,"Citadel Configuration Manager Message"); if (!IsEmptyStr(config.c_logpages)) CtdlCreateRoom(config.c_logpages, 3, "", 0, 1, 1, VIEW_BBS); /* If full text indexing has been disabled, invalidate the * index so it doesn't try to use it later. */ if (config.c_enable_fulltext == 0) { CitControl.fulltext_wordbreaker = 0; put_control(); } } else if (!strcasecmp(cmd, "GETSYS")) { extract_token(confname, argbuf, 1, '|', sizeof confname); confptr = CtdlGetSysConfig(confname); if (confptr != NULL) { long len; len = strlen(confptr); cprintf("%d %s\n", LISTING_FOLLOWS, confname); client_write(confptr, len); if ((len > 0) && (confptr[len - 1] != 10)) client_write("\n", 1); cprintf("000\n"); free(confptr); } else { cprintf("%d No such configuration.\n", ERROR + ILLEGAL_VALUE); } } else if (!strcasecmp(cmd, "PUTSYS")) { extract_token(confname, argbuf, 1, '|', sizeof confname); unbuffer_output(); cprintf("%d %s\n", SEND_LISTING, confname); confptr = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0); CtdlPutSysConfig(confname, confptr); free(confptr); } else { cprintf("%d Illegal option(s) specified.\n", ERROR + ILLEGAL_VALUE); } }
/* * Fetch a specific revision of a wiki page. The "operation" string may be set to "fetch" in order * to simply fetch the desired revision and store it in a temporary location for viewing, or "revert" * to revert the currently active page to that revision. */ void wiki_rev(char *pagename, char *rev, char *operation) { struct CitContext *CCC = CC; int r; char history_page_name[270]; long msgnum; char temp[PATH_MAX]; struct CtdlMessage *msg; FILE *fp; struct HistoryEraserCallBackData hecbd; long len = 0L; int rv; r = CtdlDoIHavePermissionToReadMessagesInThisRoom(); if (r != om_ok) { if (r == om_not_logged_in) { cprintf("%d Not logged in.\n", ERROR + NOT_LOGGED_IN); } else { cprintf("%d An unknown error has occurred.\n", ERROR); } return; } if (!strcasecmp(operation, "revert")) { r = CtdlDoIHavePermissionToPostInThisRoom(temp, sizeof temp, NULL, POST_LOGGED_IN, 0); if (r != 0) { cprintf("%d %s\n", r, temp); return; } } /* Begin by fetching the current version of the page. We're going to patch * backwards through the diffs until we get the one we want. */ msgnum = CtdlLocateMessageByEuid(pagename, &CCC->room); if (msgnum > 0L) { msg = CtdlFetchMessage(msgnum, 1, 1); } else { msg = NULL; } if ((msg != NULL) && CM_IsEmpty(msg, eMesageText)) { CM_Free(msg); msg = NULL; } if (msg == NULL) { cprintf("%d Page '%s' was not found.\n", ERROR+MESSAGE_NOT_FOUND, pagename); return; } /* Output it to a temporary file */ CtdlMakeTempFileName(temp, sizeof temp); fp = fopen(temp, "w"); if (fp != NULL) { r = fwrite(msg->cm_fields[eMesageText], msg->cm_lengths[eMesageText], 1, fp); fclose(fp); } else { syslog(LOG_ALERT, "Cannot open %s: %s\n", temp, strerror(errno)); } CM_Free(msg); /* Get the revision history */ snprintf(history_page_name, sizeof history_page_name, "%s_HISTORY_", pagename); msgnum = CtdlLocateMessageByEuid(history_page_name, &CCC->room); if (msgnum > 0L) { msg = CtdlFetchMessage(msgnum, 1, 1); } else { msg = NULL; } if ((msg != NULL) && CM_IsEmpty(msg, eMesageText)) { CM_Free(msg); msg = NULL; } if (msg == NULL) { cprintf("%d Revision history for '%s' was not found.\n", ERROR+MESSAGE_NOT_FOUND, pagename); return; } /* Start patching backwards (newest to oldest) through the revision history until we * hit the revision uuid requested by the user. (The callback will perform each one.) */ memset(&hecbd, 0, sizeof(struct HistoryEraserCallBackData)); hecbd.tempfilename = temp; hecbd.stop_when = rev; striplt(hecbd.stop_when); mime_parser(CM_RANGE(msg, eMesageText), *wiki_rev_callback, NULL, NULL, (void *)&hecbd, 0); CM_Free(msg); /* Were we successful? */ if (hecbd.done == 0) { cprintf("%d Revision '%s' of page '%s' was not found.\n", ERROR + MESSAGE_NOT_FOUND, rev, pagename ); } /* We have the desired revision on disk. Now do something with it. */ else if ( (!strcasecmp(operation, "fetch")) || (!strcasecmp(operation, "revert")) ) { msg = malloc(sizeof(struct CtdlMessage)); memset(msg, 0, sizeof(struct CtdlMessage)); msg->cm_magic = CTDLMESSAGE_MAGIC; msg->cm_anon_type = MES_NORMAL; msg->cm_format_type = FMT_RFC822; fp = fopen(temp, "r"); if (fp) { char *msgbuf; fseek(fp, 0L, SEEK_END); len = ftell(fp); fseek(fp, 0L, SEEK_SET); msgbuf = malloc(len + 1); rv = fread(msgbuf, len, 1, fp); syslog(LOG_DEBUG, "did %d blocks of %ld bytes\n", rv, len); msgbuf[len] = '\0'; CM_SetAsField(msg, eMesageText, &msgbuf, len); fclose(fp); } if (len <= 0) { msgnum = (-1L); } else if (!strcasecmp(operation, "fetch")) { CM_SetField(msg, eAuthor, HKEY("Citadel")); CtdlCreateRoom(wwm, 5, "", 0, 1, 1, VIEW_BBS); /* Not an error if already exists */ msgnum = CtdlSubmitMsg(msg, NULL, wwm, 0); /* Store the revision here */ /* * WARNING: VILE SLEAZY HACK * This will avoid the 'message xxx is not in this room' security error, * but only if the client fetches the message we just generated immediately * without first trying to perform other fetch operations. */ if (CCC->cached_msglist != NULL) { free(CCC->cached_msglist); CCC->cached_msglist = NULL; CCC->cached_num_msgs = 0; } CCC->cached_msglist = malloc(sizeof(long)); if (CCC->cached_msglist != NULL) { CCC->cached_num_msgs = 1; CCC->cached_msglist[0] = msgnum; } } else if (!strcasecmp(operation, "revert")) { CM_SetFieldLONG(msg, eTimestamp, time(NULL)); if (!IsEmptyStr(CCC->user.fullname)) { CM_SetField(msg, eAuthor, CCC->user.fullname, strlen(CCC->user.fullname)); } if (!IsEmptyStr(CCC->cs_inet_email)) { CM_SetField(msg, erFc822Addr, CCC->cs_inet_email, strlen(CCC->cs_inet_email)); } if (!IsEmptyStr(CCC->room.QRname)) { CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname)); } CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename"))); if (!IsEmptyStr(pagename)) { CM_SetField(msg, eExclusiveID, pagename, strlen(pagename)); } msgnum = CtdlSubmitMsg(msg, NULL, "", 0); /* Replace the current revision */ } else { /* Theoretically it is impossible to get here, but throw an error anyway */ msgnum = (-1L); } CM_Free(msg); if (msgnum >= 0L) { cprintf("%d %ld\n", CIT_OK, msgnum); /* Give the client a msgnum */ } else { cprintf("%d Error %ld has occurred.\n", ERROR+INTERNAL_ERROR, msgnum); } } /* We did all this work for nothing. Express anguish to the caller. */ else { cprintf("%d An unknown operation was requested.\n", ERROR+CMD_NOT_SUPPORTED); } unlink(temp); return; }
/* * create a new room */ void cmd_cre8(char *args) { int cre8_ok; char new_room_name[ROOMNAMELEN]; int new_room_type; char new_room_pass[32]; int new_room_floor; int new_room_view; char *notification_message = NULL; unsigned newflags; struct floor *fl; int avoid_access = 0; cre8_ok = extract_int(args, 0); extract_token(new_room_name, args, 1, '|', sizeof new_room_name); new_room_name[ROOMNAMELEN - 1] = 0; new_room_type = extract_int(args, 2); extract_token(new_room_pass, args, 3, '|', sizeof new_room_pass); avoid_access = extract_int(args, 5); new_room_view = extract_int(args, 6); new_room_pass[9] = 0; new_room_floor = 0; if ((IsEmptyStr(new_room_name)) && (cre8_ok == 1)) { cprintf("%d Invalid room name.\n", ERROR + ILLEGAL_VALUE); return; } if (!strcasecmp(new_room_name, MAILROOM)) { cprintf("%d '%s' already exists.\n", ERROR + ALREADY_EXISTS, new_room_name); return; } if (num_parms(args) >= 5) { fl = CtdlGetCachedFloor(extract_int(args, 4)); if (fl == NULL) { cprintf("%d Invalid floor number.\n", ERROR + INVALID_FLOOR_OPERATION); return; } else if ((fl->f_flags & F_INUSE) == 0) { cprintf("%d Invalid floor number.\n", ERROR + INVALID_FLOOR_OPERATION); return; } else { new_room_floor = extract_int(args, 4); } } if (CtdlAccessCheck(ac_logged_in)) return; if (CC->user.axlevel < CtdlGetConfigInt("c_createax") && !CC->internal_pgm) { cprintf("%d You need higher access to create rooms.\n", ERROR + HIGHER_ACCESS_REQUIRED); return; } if ((IsEmptyStr(new_room_name)) && (cre8_ok == 0)) { cprintf("%d Ok to create rooms.\n", CIT_OK); return; } if ((new_room_type < 0) || (new_room_type > 5)) { cprintf("%d Invalid room type.\n", ERROR + ILLEGAL_VALUE); return; } if (new_room_type == 5) { if (CC->user.axlevel < AxAideU) { cprintf("%d Higher access required\n", ERROR + HIGHER_ACCESS_REQUIRED); return; } } /* Check to make sure the requested room name doesn't already exist */ newflags = CtdlCreateRoom(new_room_name, new_room_type, new_room_pass, new_room_floor, 0, avoid_access, new_room_view); if (newflags == 0) { cprintf("%d '%s' already exists.\n", ERROR + ALREADY_EXISTS, new_room_name); return; } if (cre8_ok == 0) { cprintf("%d OK to create '%s'\n", CIT_OK, new_room_name); return; } /* If we reach this point, the room needs to be created. */ newflags = CtdlCreateRoom(new_room_name, new_room_type, new_room_pass, new_room_floor, 1, 0, new_room_view); /* post a message in Aide> describing the new room */ notification_message = malloc(1024); snprintf(notification_message, 1024, "A new room called \"%s\" has been created by %s%s%s%s%s%s\n", new_room_name, (CC->logged_in ? CC->curr_user : "******"), ((newflags & QR_MAILBOX) ? " [personal]" : ""), ((newflags & QR_PRIVATE) ? " [private]" : ""), ((newflags & QR_GUESSNAME) ? " [hidden]" : ""), ((newflags & QR_PASSWORDED) ? " Password: "******""), ((newflags & QR_PASSWORDED) ? new_room_pass : "") ); CtdlAideMessage(notification_message, "Room Creation Message"); free(notification_message); cprintf("%d '%s' has been created.\n", CIT_OK, new_room_name); }
/* * This is the back end for flush_conversations_to_disk() * At this point we've isolated a single conversation (struct imlog) * and are ready to write it to disk. */ void flush_individual_conversation(struct imlog *im) { struct CtdlMessage *msg; long msgnum = 0; char roomname[ROOMNAMELEN]; StrBuf *MsgBuf, *FullMsgBuf; StrBufAppendBufPlain(im->conversation, HKEY( "</body>\r\n" "</html>\r\n" ), 0 ); MsgBuf = StrBufRFC2047encodeMessage(im->conversation); FlushStrBuf(im->conversation); FullMsgBuf = NewStrBufPlain(NULL, StrLength(im->conversation) + 100); StrBufAppendBufPlain(FullMsgBuf, HKEY( "Content-type: text/html; charset=UTF-8\r\n" "Content-Transfer-Encoding: quoted-printable\r\n" "\r\n" ), 0); StrBufAppendBuf (FullMsgBuf, MsgBuf, 0); FreeStrBuf(&MsgBuf); msg = malloc(sizeof(struct CtdlMessage)); memset(msg, 0, sizeof(struct CtdlMessage)); msg->cm_magic = CTDLMESSAGE_MAGIC; msg->cm_anon_type = MES_NORMAL; msg->cm_format_type = FMT_RFC822; if (!IsEmptyStr(im->usernames[0])) { CM_SetField(msg, eAuthor, im->usernames[0], strlen(im->usernames[0])); } else { CM_SetField(msg, eAuthor, HKEY("Citadel")); } if (!IsEmptyStr(im->usernames[1])) { CM_SetField(msg, eRecipient, im->usernames[1], strlen(im->usernames[1])); } CM_SetField(msg, eOriginalRoom, HKEY(PAGELOGROOM)); CM_SetField(msg, eNodeName, CFG_KEY(c_nodename)); CM_SetAsFieldSB(msg, eMesageText, &FullMsgBuf); /* we own this memory now */ /* Start with usernums[1] because it's guaranteed to be higher than usernums[0], * so if there's only one party, usernums[0] will be zero but usernums[1] won't. * Create the room if necessary. Note that we create as a type 5 room rather * than 4, which indicates that it's a personal room but we've already supplied * the namespace prefix. * * In the unlikely event that usernums[1] is zero, a room with an invalid namespace * prefix will be created. That's ok because the auto-purger will clean it up later. */ snprintf(roomname, sizeof roomname, "%010ld.%s", im->usernums[1], PAGELOGROOM); CtdlCreateRoom(roomname, 5, "", 0, 1, 1, VIEW_BBS); msgnum = CtdlSubmitMsg(msg, NULL, roomname, 0); CM_Free(msg); /* If there is a valid user number in usernums[0], save a copy for them too. */ if (im->usernums[0] > 0) { snprintf(roomname, sizeof roomname, "%010ld.%s", im->usernums[0], PAGELOGROOM); CtdlCreateRoom(roomname, 5, "", 0, 1, 1, VIEW_BBS); CtdlSaveMsgPointerInRoom(roomname, msgnum, 0, NULL); } /* Finally, if we're logging instant messages globally, do that now. */ if (!IsEmptyStr(config.c_logpages)) { CtdlCreateRoom(config.c_logpages, 3, "", 0, 1, 1, VIEW_BBS); CtdlSaveMsgPointerInRoom(config.c_logpages, msgnum, 0, NULL); } }