- char *references /* Thread references */
- ) {
- char dest_node[256];
- char buf[1024];
- struct CtdlMessage *msg;
- StrBuf *FakeAuthor;
- StrBuf *FakeEncAuthor = NULL;
-
- msg = malloc(sizeof(struct CtdlMessage));
- memset(msg, 0, sizeof(struct CtdlMessage));
- msg->cm_magic = CTDLMESSAGE_MAGIC;
- msg->cm_anon_type = type;
- msg->cm_format_type = format_type;
-
- /* Don't confuse the poor folks if it's not routed mail. */
- strcpy(dest_node, "");
-
- if (recipient != NULL) striplt(recipient);
- if (recp_cc != NULL) striplt(recp_cc);
-
- /* Path or Return-Path */
- if (my_email == NULL) my_email = "";
-
- if (!IsEmptyStr(my_email)) {
- msg->cm_fields['P'] = strdup(my_email);
- }
- else {
- snprintf(buf, sizeof buf, "%s", author->fullname);
- msg->cm_fields['P'] = strdup(buf);
- }
- convert_spaces_to_underscores(msg->cm_fields['P']);
-
- snprintf(buf, sizeof buf, "%ld", (long)time(NULL)); /* timestamp */
- msg->cm_fields['T'] = strdup(buf);
-
- if ((fake_name != NULL) && (fake_name[0])) { /* author */
- FakeAuthor = NewStrBufPlain (fake_name, -1);
- }
- else {
- FakeAuthor = NewStrBufPlain (author->fullname, -1);
- }
- StrBufRFC2047encode(&FakeEncAuthor, FakeAuthor);
- msg->cm_fields['A'] = SmashStrBuf(&FakeEncAuthor);
- FreeStrBuf(&FakeAuthor);
-
- if (CC->room.QRflags & QR_MAILBOX) { /* room */
- msg->cm_fields['O'] = strdup(&CC->room.QRname[11]);
- }
- else {
- msg->cm_fields['O'] = strdup(CC->room.QRname);
- }
-
- msg->cm_fields['N'] = strdup(NODENAME); /* nodename */
- msg->cm_fields['H'] = strdup(HUMANNODE); /* hnodename */
-
- if ((recipient != NULL) && (recipient[0] != 0)) {
- msg->cm_fields['R'] = strdup(recipient);
- }
- if ((recp_cc != NULL) && (recp_cc[0] != 0)) {
- msg->cm_fields['Y'] = strdup(recp_cc);
- }
- if (dest_node[0] != 0) {
- msg->cm_fields['D'] = strdup(dest_node);
- }
-
- if (!IsEmptyStr(my_email)) {
- msg->cm_fields['F'] = strdup(my_email);
- }
- else if ( (author == &CC->user) && (!IsEmptyStr(CC->cs_inet_email)) ) {
- msg->cm_fields['F'] = strdup(CC->cs_inet_email);
- }
-
- if (subject != NULL) {
- long length;
- striplt(subject);
- length = strlen(subject);
- if (length > 0) {
- long i;
- long IsAscii;
- IsAscii = -1;
- i = 0;
- while ((subject[i] != '\0') &&
- (IsAscii = isascii(subject[i]) != 0 ))
- i++;
- if (IsAscii != 0)
- msg->cm_fields['U'] = strdup(subject);
- else /* ok, we've got utf8 in the string. */
- {
- msg->cm_fields['U'] = rfc2047encode(subject, length);
- }
-
- }
- }
-
- if (supplied_euid != NULL) {
- msg->cm_fields['E'] = strdup(supplied_euid);
- }
-
- if ((references != NULL) && (!IsEmptyStr(references))) {
- if (msg->cm_fields['W'] != NULL)
- free(msg->cm_fields['W']);
- msg->cm_fields['W'] = strdup(references);
- }
-
- if (preformatted_text != NULL) {
- msg->cm_fields['M'] = preformatted_text;
- }
- else {
- msg->cm_fields['M'] = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0);
- }
-
- return(msg);
-}
-
-extern int netconfig_check_roomaccess(
- char *errmsgbuf,
- size_t n,
- const char* RemoteIdentifier); /* TODO: find a smarter way */
-
-/*
- * Check to see whether we have permission to post a message in the current
- * room. Returns a *CITADEL ERROR CODE* and puts a message in errmsgbuf, or
- * returns 0 on success.
- */
-int CtdlDoIHavePermissionToPostInThisRoom(
- char *errmsgbuf,
- size_t n,
- const char* RemoteIdentifier,
- int PostPublic,
- int is_reply
- ) {
- int ra;
-
- if (!(CC->logged_in) &&
- (PostPublic == POST_LOGGED_IN)) {
- snprintf(errmsgbuf, n, "Not logged in.");
- return (ERROR + NOT_LOGGED_IN);
- }
- else if (PostPublic == CHECK_EXISTANCE) {
- return (0); // We're Evaling whether a recipient exists
- }
- else if (!(CC->logged_in)) {
-
- if ((CC->room.QRflags & QR_READONLY)) {
- snprintf(errmsgbuf, n, "Not logged in.");
- return (ERROR + NOT_LOGGED_IN);
- }
- if (CC->room.QRflags2 & QR2_MODERATED) {
- snprintf(errmsgbuf, n, "Not logged in Moderation feature not yet implemented!");
- return (ERROR + NOT_LOGGED_IN);
- }
- if ((PostPublic!=POST_LMTP) &&(CC->room.QRflags2 & QR2_SMTP_PUBLIC) == 0) {
-
- return netconfig_check_roomaccess(errmsgbuf, n, RemoteIdentifier);
- }
- return (0);
-
- }
-
- if ((CC->user.axlevel < AxProbU)
- && ((CC->room.QRflags & QR_MAILBOX) == 0)) {
- snprintf(errmsgbuf, n, "Need to be validated to enter (except in %s> to sysop)", MAILROOM);
- return (ERROR + HIGHER_ACCESS_REQUIRED);
- }
-
- CtdlRoomAccess(&CC->room, &CC->user, &ra, NULL);
-
- if (ra & UA_POSTALLOWED) {
- strcpy(errmsgbuf, "OK to post or reply here");
- return(0);
- }
-
- if ( (ra & UA_REPLYALLOWED) && (is_reply) ) {
- /*
- * To be thorough, we ought to check to see if the message they are
- * replying to is actually a valid one in this room, but unless this
- * actually becomes a problem we'll go with high performance instead.
- */
- strcpy(errmsgbuf, "OK to reply here");
- return(0);
- }
-
- if ( (ra & UA_REPLYALLOWED) && (!is_reply) ) {
- /* Clarify what happened with a better error message */
- snprintf(errmsgbuf, n, "You may only reply to existing messages here.");
- return (ERROR + HIGHER_ACCESS_REQUIRED);
- }
-
- snprintf(errmsgbuf, n, "Higher access is required to post in this room.");
- return (ERROR + HIGHER_ACCESS_REQUIRED);
-
-}
-
-
-/*
- * Check to see if the specified user has Internet mail permission
- * (returns nonzero if permission is granted)
- */
-int CtdlCheckInternetMailPermission(struct ctdluser *who) {
-
- /* Do not allow twits to send Internet mail */
- if (who->axlevel <= AxProbU) return(0);
-
- /* Globally enabled? */
- if (config.c_restrict == 0) return(1);
-
- /* User flagged ok? */
- if (who->flags & US_INTERNET) return(2);
-
- /* Aide level access? */
- if (who->axlevel >= AxAideU) return(3);
-
- /* No mail for you! */
- return(0);
-}
-
-
-/*
- * Validate recipients, count delivery types and errors, and handle aliasing
- * FIXME check for dupes!!!!!
- *
- * Returns 0 if all addresses are ok, ret->num_error = -1 if no addresses
- * were specified, or the number of addresses found invalid.
- *
- * Caller needs to free the result using free_recipients()
- */
-struct recptypes *validate_recipients(const char *supplied_recipients,
- const char *RemoteIdentifier,
- int Flags) {
- struct CitContext *CCC = CC;
- struct recptypes *ret;
- char *recipients = NULL;
- char *org_recp;
- char this_recp[256];
- char this_recp_cooked[256];
- char append[SIZ];
- long len;
- int num_recps = 0;
- int i, j;
- int mailtype;
- int invalid;
- struct ctdluser tempUS;
- struct ctdlroom tempQR;
- struct ctdlroom tempQR2;
- int err = 0;
- char errmsg[SIZ];
- int in_quotes = 0;
-
- /* Initialize */
- ret = (struct recptypes *) malloc(sizeof(struct recptypes));
- if (ret == NULL) return(NULL);
-
- /* Set all strings to null and numeric values to zero */
- memset(ret, 0, sizeof(struct recptypes));
-
- if (supplied_recipients == NULL) {
- recipients = strdup("");
- }
- else {
- recipients = strdup(supplied_recipients);
- }
-
- /* Allocate some memory. Yes, this allocates 500% more memory than we will
- * actually need, but it's healthier for the heap than doing lots of tiny
- * realloc() calls instead.
- */
- len = strlen(recipients) + 1024;
- ret->errormsg = malloc(len);
- ret->recp_local = malloc(len);
- ret->recp_internet = malloc(len);
- ret->recp_ignet = malloc(len);
- ret->recp_room = malloc(len);
- ret->display_recp = malloc(len);
- ret->recp_orgroom = malloc(len);
- org_recp = malloc(len);
-
- ret->errormsg[0] = 0;
- ret->recp_local[0] = 0;
- ret->recp_internet[0] = 0;
- ret->recp_ignet[0] = 0;
- ret->recp_room[0] = 0;
- ret->recp_orgroom[0] = 0;
- ret->display_recp[0] = 0;
-
- ret->recptypes_magic = RECPTYPES_MAGIC;
-
- /* Change all valid separator characters to commas */
- for (i=0; !IsEmptyStr(&recipients[i]); ++i) {
- if ((recipients[i] == ';') || (recipients[i] == '|')) {
- recipients[i] = ',';
- }
- }
-
- /* Now start extracting recipients... */
-
- while (!IsEmptyStr(recipients)) {
- for (i=0; i<=strlen(recipients); ++i) {
- if (recipients[i] == '\"') in_quotes = 1 - in_quotes;
- if ( ( (recipients[i] == ',') && (!in_quotes) ) || (recipients[i] == 0) ) {
- safestrncpy(this_recp, recipients, i+1);
- this_recp[i] = 0;
- if (recipients[i] == ',') {
- strcpy(recipients, &recipients[i+1]);
- }
- else {
- strcpy(recipients, "");
- }
- break;
- }
- }
-
- striplt(this_recp);
- if (IsEmptyStr(this_recp))
- break;
- MSG_syslog(LOG_DEBUG, "Evaluating recipient #%d: %s\n", num_recps, this_recp);
- ++num_recps;
-
- strcpy(org_recp, this_recp);
- alias(this_recp);
- alias(this_recp);
- mailtype = alias(this_recp);
-
- for (j = 0; !IsEmptyStr(&this_recp[j]); ++j) {
- if (this_recp[j]=='_') {
- this_recp_cooked[j] = ' ';
- }
- else {
- this_recp_cooked[j] = this_recp[j];
- }
- }
- this_recp_cooked[j] = '\0';
- invalid = 0;
- errmsg[0] = 0;
- switch(mailtype) {
- case MES_LOCAL:
- if (!strcasecmp(this_recp, "sysop")) {
- ++ret->num_room;
- strcpy(this_recp, config.c_aideroom);
- if (!IsEmptyStr(ret->recp_room)) {
- strcat(ret->recp_room, "|");
- }
- strcat(ret->recp_room, this_recp);
- }
- else if ( (!strncasecmp(this_recp, "room_", 5))
- && (!CtdlGetRoom(&tempQR, &this_recp_cooked[5])) ) {
-
- /* Save room so we can restore it later */
- tempQR2 = CCC->room;
- CCC->room = tempQR;
-
- /* Check permissions to send mail to this room */
- err = CtdlDoIHavePermissionToPostInThisRoom(
- errmsg,
- sizeof errmsg,
- RemoteIdentifier,
- Flags,
- 0 /* 0 = not a reply */
- );
- if (err)
- {
- ++ret->num_error;
- invalid = 1;
- }
- else {
- ++ret->num_room;
- if (!IsEmptyStr(ret->recp_room)) {
- strcat(ret->recp_room, "|");
- }
- strcat(ret->recp_room, &this_recp_cooked[5]);
-
- if (!IsEmptyStr(ret->recp_orgroom)) {
- strcat(ret->recp_orgroom, "|");
- }
- strcat(ret->recp_orgroom, org_recp);
-
- }
-
- /* Restore room in case something needs it */
- CCC->room = tempQR2;
-
- }
- else if (CtdlGetUser(&tempUS, this_recp) == 0) {
- ++ret->num_local;
- strcpy(this_recp, tempUS.fullname);
- if (!IsEmptyStr(ret->recp_local)) {
- strcat(ret->recp_local, "|");
- }
- strcat(ret->recp_local, this_recp);
- }
- else if (CtdlGetUser(&tempUS, this_recp_cooked) == 0) {
- ++ret->num_local;
- strcpy(this_recp, tempUS.fullname);
- if (!IsEmptyStr(ret->recp_local)) {
- strcat(ret->recp_local, "|");
- }
- strcat(ret->recp_local, this_recp);
- }
- else {
- ++ret->num_error;
- invalid = 1;
- }
- break;
- case MES_INTERNET:
- /* Yes, you're reading this correctly: if the target
- * domain points back to the local system or an attached
- * Citadel directory, the address is invalid. That's
- * because if the address were valid, we would have
- * already translated it to a local address by now.
- */
- if (IsDirectory(this_recp, 0)) {
- ++ret->num_error;
- invalid = 1;
- }
- else {
- ++ret->num_internet;
- if (!IsEmptyStr(ret->recp_internet)) {
- strcat(ret->recp_internet, "|");
- }
- strcat(ret->recp_internet, this_recp);
- }
- break;
- case MES_IGNET:
- ++ret->num_ignet;
- if (!IsEmptyStr(ret->recp_ignet)) {
- strcat(ret->recp_ignet, "|");
- }
- strcat(ret->recp_ignet, this_recp);
- break;
- case MES_ERROR:
- ++ret->num_error;
- invalid = 1;
- break;
- }
- if (invalid) {
- if (IsEmptyStr(errmsg)) {
- snprintf(append, sizeof append, "Invalid recipient: %s", this_recp);
- }
- else {
- snprintf(append, sizeof append, "%s", errmsg);
- }
- if ( (strlen(ret->errormsg) + strlen(append) + 3) < SIZ) {
- if (!IsEmptyStr(ret->errormsg)) {
- strcat(ret->errormsg, "; ");
- }
- strcat(ret->errormsg, append);
- }
- }
- else {
- if (IsEmptyStr(ret->display_recp)) {
- strcpy(append, this_recp);
- }
- else {
- snprintf(append, sizeof append, ", %s", this_recp);
- }
- if ( (strlen(ret->display_recp)+strlen(append)) < SIZ) {
- strcat(ret->display_recp, append);
- }
- }
- }
- free(org_recp);
-
- if ((ret->num_local + ret->num_internet + ret->num_ignet +
- ret->num_room + ret->num_error) == 0) {
- ret->num_error = (-1);
- strcpy(ret->errormsg, "No recipients specified.");
- }
-
- MSGM_syslog(LOG_DEBUG, "validate_recipients()\n");
- MSG_syslog(LOG_DEBUG, " local: %d <%s>\n", ret->num_local, ret->recp_local);
- MSG_syslog(LOG_DEBUG, " room: %d <%s>\n", ret->num_room, ret->recp_room);
- MSG_syslog(LOG_DEBUG, " inet: %d <%s>\n", ret->num_internet, ret->recp_internet);
- MSG_syslog(LOG_DEBUG, " ignet: %d <%s>\n", ret->num_ignet, ret->recp_ignet);
- MSG_syslog(LOG_DEBUG, " error: %d <%s>\n", ret->num_error, ret->errormsg);
-
- free(recipients);
- return(ret);
-}
-
-
-/*
- * Destructor for struct recptypes
- */
-void free_recipients(struct recptypes *valid) {
-
- if (valid == NULL) {
- return;
- }
-
- if (valid->recptypes_magic != RECPTYPES_MAGIC) {
- struct CitContext *CCC = CC;
- MSGM_syslog(LOG_EMERG, "Attempt to call free_recipients() on some other data type!\n");
- abort();
- }
-
- if (valid->errormsg != NULL) free(valid->errormsg);
- if (valid->recp_local != NULL) free(valid->recp_local);
- if (valid->recp_internet != NULL) free(valid->recp_internet);
- if (valid->recp_ignet != NULL) free(valid->recp_ignet);
- if (valid->recp_room != NULL) free(valid->recp_room);
- if (valid->recp_orgroom != NULL) free(valid->recp_orgroom);
- if (valid->display_recp != NULL) free(valid->display_recp);
- if (valid->bounce_to != NULL) free(valid->bounce_to);
- if (valid->envelope_from != NULL) free(valid->envelope_from);
- if (valid->sending_room != NULL) free(valid->sending_room);
- free(valid);
-}
-
-
-
-/*
- * message entry - mode 0 (normal)
- */
-void cmd_ent0(char *entargs)