Esempio n. 1
0
/**
 * this one has to have the context for loading the message via the redirect buffer...
 */
StrBuf *smtp_load_msg(OneQueItem *MyQItem, int n, char **Author, char **Address)
{
	CitContext *CCC=CC;
	StrBuf *SendMsg;

	CCC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
	CtdlOutputMsg(MyQItem->MessageID,
		      MT_RFC822, HEADERS_ALL,
		      0, 1, NULL,
		      (ESC_DOT|SUPPRESS_ENV_TO),
		      Author,
		      Address,
			NULL);

	SendMsg = CCC->redirect_buffer;
	CCC->redirect_buffer = NULL;
	if ((StrLength(SendMsg) > 0) &&
	    ChrPtr(SendMsg)[StrLength(SendMsg) - 1] != '\n') {
		SMTPC_syslog(LOG_WARNING,
			     "[%d] Possible problem: message did not "
			     "correctly terminate. (expecting 0x10, got 0x%02x)\n",
			     MsgCount, //yes uncool, but best choice here...
			     ChrPtr(SendMsg)[StrLength(SendMsg) - 1] );
		StrBufAppendBufPlain(SendMsg, HKEY("\r\n"), 0);
	}
	return SendMsg;
}
Esempio n. 2
0
//
// Utility function for nntp_last_next() that turns a msgnum into a message ID.
// The memory for the returned string is pwnz0red by the caller.
//
char *message_id_from_msgnum(long msgnum) {

	char *fetched_message_id = NULL;
	CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
	CtdlOutputMsg(msgnum,
			MT_RFC822,		// output in RFC822 format ... sort of
			HEADERS_FAST,		// headers, body, or both?
			0,			// don't do Citadel protocol responses
			1,			// CRLF newlines
			NULL,			// teh whole thing, not just a section
			0,			// no flags yet ... maybe new ones for Path: etc ?
			NULL,
			NULL,
			&fetched_message_id	// extract the message ID from the message as we go...
	);
	StrBuf *msgtext = CC->redirect_buffer;
	CC->redirect_buffer = NULL;

	FreeStrBuf(&msgtext);
	return(fetched_message_id);
}
Esempio n. 3
0
/*
 * smtp_do_bounce() is caled by smtp_do_procmsg() to scan a set of delivery
 * instructions for "5" codes (permanent fatal errors) and produce/deliver
 * a "bounce" message (delivery status notification).
 */
void smtp_do_bounce(char *instr, StrBuf *OMsgTxt)
{
	int i;
	int lines;
	int status;
	char buf[1024];
	char key[1024];
	char addr[1024];
	char dsn[1024];
	char bounceto[1024];
	StrBuf *boundary;
	int num_bounces = 0;
	int bounce_this = 0;
	time_t submitted = 0L;
	struct CtdlMessage *bmsg = NULL;
	int give_up = 0;
	recptypes *valid;
	int successful_bounce = 0;
	static int seq = 0;
	StrBuf *BounceMB;
	long omsgid = (-1);

	syslog(LOG_DEBUG, "smtp_do_bounce() called\n");
	strcpy(bounceto, "");
	boundary = NewStrBufPlain(HKEY("=_Citadel_Multipart_"));

	StrBufAppendPrintf(boundary, "%s_%04x%04x", CtdlGetConfigStr("c_fqdn"), getpid(), ++seq);

	lines = num_tokens(instr, '\n');

	/* See if it's time to give up on delivery of this message */
	for (i=0; i<lines; ++i) {
		extract_token(buf, instr, i, '\n', sizeof buf);
		extract_token(key, buf, 0, '|', sizeof key);
		extract_token(addr, buf, 1, '|', sizeof addr);
		if (!strcasecmp(key, "submitted")) {
			submitted = atol(addr);
		}
	}

	if ( (time(NULL) - submitted) > SMTP_GIVE_UP ) {
		give_up = 1;
	}

	/* Start building our bounce message */

	bmsg = (struct CtdlMessage *) malloc(sizeof(struct CtdlMessage));
	if (bmsg == NULL) return;
	memset(bmsg, 0, sizeof(struct CtdlMessage));
	BounceMB = NewStrBufPlain(NULL, 1024);

	bmsg->cm_magic = CTDLMESSAGE_MAGIC;
	bmsg->cm_anon_type = MES_NORMAL;
	bmsg->cm_format_type = FMT_RFC822;
	CM_SetField(bmsg, eAuthor, HKEY("Citadel"));
	CM_SetField(bmsg, eOriginalRoom, HKEY(MAILROOM));
	CM_SetField(bmsg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
	CM_SetField(bmsg, eMsgSubject, HKEY("Delivery Status Notification (Failure)"));
	StrBufAppendBufPlain(BounceMB, HKEY("Content-type: multipart/mixed; boundary=\""), 0);
	StrBufAppendBuf(BounceMB, boundary, 0);
	StrBufAppendBufPlain(BounceMB, HKEY("\"\r\n"), 0);
	StrBufAppendBufPlain(BounceMB, HKEY("MIME-Version: 1.0\r\n"), 0);
	StrBufAppendBufPlain(BounceMB, HKEY("X-Mailer: " CITADEL "\r\n"), 0);

	StrBufAppendBufPlain(
		BounceMB,
		HKEY("\r\nThis is a multipart message in MIME format."
		     "\r\n\r\n"), 0);

	StrBufAppendBufPlain(BounceMB, HKEY("--"), 0);
	StrBufAppendBuf(BounceMB, boundary, 0);
	StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);
	StrBufAppendBufPlain(BounceMB,
			     HKEY("Content-type: text/plain\r\n\r\n"), 0);

	if (give_up)
	{
		StrBufAppendBufPlain(
			BounceMB,
			HKEY("A message you sent could not be delivered "
			     "to some or all of its recipients\ndue to "
			     "prolonged unavailability of its destination(s).\n"
			     "Giving up on the following addresses:\n\n"), 0);
	}
	else
	{
		StrBufAppendBufPlain(
			BounceMB,
			HKEY("A message you sent could not be delivered "
			     "to some or all of its recipients.\n"
			     "The following addresses were undeliverable:\n\n"
				), 0);
	}

	/*
	 * Now go through the instructions checking for stuff.
	 */
	for (i=0; i<lines; ++i) {
		long addrlen;
		long dsnlen;
		extract_token(buf, instr, i, '\n', sizeof buf);
		extract_token(key, buf, 0, '|', sizeof key);
		addrlen = extract_token(addr, buf, 1, '|', sizeof addr);
		status = extract_int(buf, 2);
		dsnlen = extract_token(dsn, buf, 3, '|', sizeof dsn);
		bounce_this = 0;

		syslog(LOG_DEBUG, "key=<%s> addr=<%s> status=%d dsn=<%s>\n",
		       key, addr, status, dsn);

		if (!strcasecmp(key, "bounceto")) {
			strcpy(bounceto, addr);
		}

		if (!strcasecmp(key, "msgid")) {
			omsgid = atol(addr);
		}

		if (!strcasecmp(key, "remote")) {
			if (status == 5) bounce_this = 1;
			if (give_up) bounce_this = 1;
		}

		if (bounce_this) {
			++num_bounces;

			StrBufAppendBufPlain(BounceMB, addr, addrlen, 0);
			StrBufAppendBufPlain(BounceMB, HKEY(": "), 0);
			StrBufAppendBufPlain(BounceMB, dsn, dsnlen, 0);
			StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);

			remove_token(instr, i, '\n');
			--i;
			--lines;
		}
	}

	/* Attach the original message */
	if (omsgid >= 0) {
		StrBufAppendBufPlain(BounceMB, HKEY("--"), 0);
		StrBufAppendBuf(BounceMB, boundary, 0);
		StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);

		StrBufAppendBufPlain(
			BounceMB,
			HKEY("Content-type: message/rfc822\r\n"), 0);

		StrBufAppendBufPlain(
			BounceMB,
			HKEY("Content-Transfer-Encoding: 7bit\r\n"), 0);

		StrBufAppendBufPlain(
			BounceMB,
			HKEY("Content-Disposition: inline\r\n"), 0);

		StrBufAppendBufPlain(BounceMB, HKEY("\r\n"), 0);

		if (OMsgTxt == NULL) {
			CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
			CtdlOutputMsg(omsgid,
				      MT_RFC822,
				      HEADERS_ALL,
				      0, 1, NULL, 0,
				      NULL, NULL, NULL);

			StrBufAppendBuf(BounceMB, CC->redirect_buffer, 0);
			FreeStrBuf(&CC->redirect_buffer);
		}
		else {
			StrBufAppendBuf(BounceMB, OMsgTxt, 0);
		}
	}

	/* Close the multipart MIME scope */
	StrBufAppendBufPlain(BounceMB, HKEY("--"), 0);
	StrBufAppendBuf(BounceMB, boundary, 0);
	StrBufAppendBufPlain(BounceMB, HKEY("--\r\n"), 0);
	CM_SetAsFieldSB(bmsg, eMesageText, &BounceMB);

	/* Deliver the bounce if there's anything worth mentioning */
	syslog(LOG_DEBUG, "num_bounces = %d\n", num_bounces);
	if (num_bounces > 0) {

		/* First try the user who sent the message */
		if (IsEmptyStr(bounceto))
			syslog(LOG_ERR, "No bounce address specified\n");
		else
			syslog(LOG_DEBUG, "bounce to user <%s>\n", bounceto);
		/* Can we deliver the bounce to the original sender? */
		valid = validate_recipients(bounceto,
					    smtp_get_Recipients (),
					    0);
		if (valid != NULL) {
			if (valid->num_error == 0) {
				CtdlSubmitMsg(bmsg, valid, "", QP_EADDR);
				successful_bounce = 1;
			}
		}

		/* If not, post it in the Aide> room */
		if (successful_bounce == 0) {
			CtdlSubmitMsg(bmsg, NULL, CtdlGetConfigStr("c_aideroom"), QP_EADDR);
		}

		/* Free up the memory we used */
		if (valid != NULL) {
			free_recipients(valid);
		}
	}
	FreeStrBuf(&boundary);
	CM_Free(bmsg);
	syslog(LOG_DEBUG, "Done processing bounces\n");
}
Esempio n. 4
0
//
// Implements the ARTICLE, HEAD, BODY, and STAT commands.
// (These commands all accept the same parameters; they differ only in how they output the retrieved message.)
//
void nntp_article(const char *cmd) {
	if (CtdlAccessCheck(ac_logged_in_or_guest)) return;

	citnntp *nntpstate = (citnntp *) CC->session_specific_data;
	char which_command[16];
	int acmd = 0;
	char requested_article[256];
	long requested_msgnum = 0;
	char *lb, *rb = NULL;
	int must_change_currently_selected_article = 0;

	// We're going to store one of these values in the variable 'acmd' so that
	// we can quickly check later which version of the output we want.
	enum {
		ARTICLE,
		HEAD,
		BODY,
		STAT
	};

	extract_token(which_command, cmd, 0, ' ', sizeof which_command);

	if (!strcasecmp(which_command, "article")) {
		acmd = ARTICLE;
	}
	else if (!strcasecmp(which_command, "head")) {
		acmd = HEAD;
	}
	else if (!strcasecmp(which_command, "body")) {
		acmd = BODY;
	}
	else if (!strcasecmp(which_command, "stat")) {
		acmd = STAT;
	}
	else {
		cprintf("500 I'm afraid I can't do that.\r\n");
		return;
	}

	// Which NNTP command was issued, determines whether we will fetch headers, body, or both.
	int			headers_only = HEADERS_ALL;
	if (acmd == HEAD)	headers_only = HEADERS_FAST;
	else if (acmd == BODY)	headers_only = HEADERS_NONE;
	else if (acmd == STAT)	headers_only = HEADERS_FAST;

	// now figure out what the client is asking for.
	extract_token(requested_article, cmd, 1, ' ', sizeof requested_article);
	lb = strchr(requested_article, '<');
	rb = strchr(requested_article, '>');
	requested_msgnum = atol(requested_article);

	// If no article number or message-id is specified, the client wants the "currently selected article"
	if (IsEmptyStr(requested_article)) {
		if (nntpstate->current_article_number < 1) {
			cprintf("420 No current article selected\r\n");
			return;
		}
		requested_msgnum = nntpstate->current_article_number;
		must_change_currently_selected_article = 1;
		// got it -- now fall through and keep going
	}

	// If the requested article is numeric, it maps directly to a message number.  Good.
	else if (requested_msgnum > 0) {
		must_change_currently_selected_article = 1;
		// good -- fall through and keep going
	}

	// If the requested article has angle brackets, the client wants a specific message-id.
	// We don't know how to do that yet.
	else if ( (lb != NULL) && (rb != NULL) && (lb < rb) ) {
		must_change_currently_selected_article = 0;
		cprintf("500 I don't know how to fetch by message-id yet.\r\n");	// FIXME
		return;
	}

	// Anything else is noncompliant gobbledygook and should die in a car fire.
	else {
		must_change_currently_selected_article = 0;
		cprintf("500 syntax error\r\n");
		return;
	}

	// At this point we know the message number of the "article" being requested.
	// We have an awesome API call that does all the heavy lifting for us.
	char *fetched_message_id = NULL;
	CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
	int fetch = CtdlOutputMsg(requested_msgnum,
			MT_RFC822,		// output in RFC822 format ... sort of
			headers_only,		// headers, body, or both?
			0,			// don't do Citadel protocol responses
			1,			// CRLF newlines
			NULL,			// teh whole thing, not just a section
			0,			// no flags yet ... maybe new ones for Path: etc ?
			NULL,
			NULL,
			&fetched_message_id	// extract the message ID from the message as we go...
	);
	StrBuf *msgtext = CC->redirect_buffer;
	CC->redirect_buffer = NULL;

	if (fetch != om_ok) {
		cprintf("423 no article with that number\r\n");
		FreeStrBuf(&msgtext);
		return;
	}

	// RFC3977 6.2.1.2 specifes conditions under which the "currently selected article"
	// MUST or MUST NOT be set to the message we just referenced.
	if (must_change_currently_selected_article) {
		nntpstate->current_article_number = requested_msgnum;
	}

	// Now give the client what it asked for.
	if (acmd == ARTICLE) {
		cprintf("220 %ld <%s>\r\n", requested_msgnum, fetched_message_id);
	}
	if (acmd == HEAD) {
		cprintf("221 %ld <%s>\r\n", requested_msgnum, fetched_message_id);
	}
	if (acmd == BODY) {
		cprintf("222 %ld <%s>\r\n", requested_msgnum, fetched_message_id);
	}
	if (acmd == STAT) {
		cprintf("223 %ld <%s>\r\n", requested_msgnum, fetched_message_id);
		FreeStrBuf(&msgtext);
		return;
	}

	client_write(SKEY(msgtext));
	cprintf(".\r\n");			// this protocol uses a dot terminator
	FreeStrBuf(&msgtext);
	if (fetched_message_id) free(fetched_message_id);
}