Beispiel #1
0
/*
 * This function is called by the XMPP service's async loop.
 * If the client session has instant messages waiting, it outputs
 * unsolicited XML stanzas containing them.
 */
void xmpp_output_incoming_messages(void) {

	struct ExpressMessage *ptr;
	char xmlbuf1[4096];
	char xmlbuf2[4096];

	while (CC->FirstExpressMessage != NULL) {

		begin_critical_section(S_SESSION_TABLE);
		ptr = CC->FirstExpressMessage;
		CC->FirstExpressMessage = CC->FirstExpressMessage->next;
		end_critical_section(S_SESSION_TABLE);

		cprintf("<message to=\"%s\" from=\"%s\" type=\"chat\">",
			xmlesc(xmlbuf1, XMPP->client_jid, sizeof xmlbuf1),
			xmlesc(xmlbuf2, ptr->sender_email, sizeof xmlbuf2)
		);
		if (ptr->text != NULL) {
			striplt(ptr->text);
			cprintf("<body>%s</body>", xmlesc(xmlbuf1, ptr->text, sizeof xmlbuf1));
			free(ptr->text);
		}
		cprintf("</message>");
		free(ptr);
	}
}
Beispiel #2
0
/*
 * USER cmd
 */
void cmd_user(char *cmdbuf)
{
	char username[256];
	int a;

	CON_syslog(LOG_DEBUG, "cmd_user(%s)\n", cmdbuf);
	extract_token(username, cmdbuf, 0, '|', sizeof username);
	CON_syslog(LOG_DEBUG, "username: %s\n", username);
	striplt(username);
	CON_syslog(LOG_DEBUG, "username: %s\n", username);

	a = CtdlLoginExistingUser(NULL, username);
	switch (a) {
	case login_already_logged_in:
		cprintf("%d Already logged in.\n", ERROR + ALREADY_LOGGED_IN);
		return;
	case login_too_many_users:
		cprintf("%d %s: "
			"Too many users are already online "
			"(maximum is %d)\n",
			ERROR + MAX_SESSIONS_EXCEEDED,
			CtdlGetConfigStr("c_nodename"), CtdlGetConfigInt("c_maxsessions"));
		return;
	case login_ok:
		cprintf("%d Password required for %s\n",
			MORE_DATA, CC->curr_user);
		return;
	case login_not_found:
		cprintf("%d %s not found.\n", ERROR + NO_SUCH_USER, username);
		return;
	default:
		cprintf("%d Internal error\n", ERROR + INTERNAL_ERROR);
	}
}
Beispiel #3
0
/* 
 *  List users (searchstring may be empty to list all users)
 */
void cmd_list(char *cmdbuf)
{
	char searchstring[256];
	extract_token(searchstring, cmdbuf, 0, '|', sizeof searchstring);
	striplt(searchstring);
	cprintf("%d \n", LISTING_FOLLOWS);
	ForEachUser(ListThisUser, (void *)searchstring );
	cprintf("000\n");
}
/*
 * Look for a particular header field in an RFC822 message text.  If the
 * requested field is found, it is unfolded (if necessary) and returned to
 * the caller.  The field name is stripped out, leaving only its contents.
 * The caller is responsible for freeing the returned buffer.  If the requested
 * field is not present, or anything else goes wrong, it returns NULL.
 */
char *rfc822_fetch_field(const char *rfc822, const char *fieldname) {
	char *fieldbuf = NULL;
	const char *end_of_headers;
	const char *field_start;
	const char *ptr;
	char *cont;
	char fieldhdr[SIZ];

	/* Should never happen, but sometimes we get stupid */
	if (rfc822 == NULL) return(NULL);
	if (fieldname == NULL) return(NULL);

	snprintf(fieldhdr, sizeof fieldhdr, "%s:", fieldname);

	/* Locate the end of the headers, so we don't run past that point */
	end_of_headers = cbmstrcasestr(rfc822, "\n\r\n");
	if (end_of_headers == NULL) {
		end_of_headers = cbmstrcasestr(rfc822, "\n\n");
	}
	if (end_of_headers == NULL) return (NULL);

	field_start = cbmstrcasestr(rfc822, fieldhdr);
	if (field_start == NULL) return(NULL);
	if (field_start > end_of_headers) return(NULL);

	fieldbuf = malloc(SIZ);
	strcpy(fieldbuf, "");

	ptr = field_start;
	ptr = cmemreadline(ptr, fieldbuf, SIZ-strlen(fieldbuf) );
	while ( (isspace(ptr[0])) && (ptr < end_of_headers) ) {
		strcat(fieldbuf, " ");
		cont = &fieldbuf[strlen(fieldbuf)];
		ptr = cmemreadline(ptr, cont, SIZ-strlen(fieldbuf) );
		striplt(cont);
	}

	strcpy(fieldbuf, &fieldbuf[strlen(fieldhdr)]);
	striplt(fieldbuf);

	return(fieldbuf);
}
Beispiel #5
0
/*
 * MIME Parser callback for wiki_rev()
 *
 * The "filename" field will contain a memo field, which includes (among other things)
 * the uuid of this revision.  After we hit the desired revision, we stop processing.
 *
 * The "content" filed will contain "diff" output suitable for applying via "patch"
 * to our temporary file.
 */
void wiki_rev_callback(char *name, char *filename, char *partnum, char *disp,
		   void *content, char *cbtype, char *cbcharset, size_t length,
		   char *encoding, char *cbid, void *cbuserdata)
{
	struct HistoryEraserCallBackData *hecbd = (struct HistoryEraserCallBackData *)cbuserdata;
	char memo[1024];
	char this_rev[256];
	FILE *fp;
	char *ptr = NULL;
	char buf[1024];

	/* Did a previous callback already indicate that we've reached our target uuid?
	 * If so, don't process anything else.
	 */
	if (hecbd->done) {
		return;
	}

	CtdlDecodeBase64(memo, filename, strlen(filename));
	extract_token(this_rev, memo, 0, '|', sizeof this_rev);
	striplt(this_rev);

	/* Perform the patch */
	fp = popen(PATCH " -f -s -p0 -r /dev/null >/dev/null 2>/dev/null", "w");
	if (fp) {
		/* Replace the filenames in the patch with the tempfilename we're actually tweaking */
		fprintf(fp, "--- %s\n", hecbd->tempfilename);
		fprintf(fp, "+++ %s\n", hecbd->tempfilename);

		ptr = (char *)content;
		int linenum = 0;
		do {
			++linenum;
			ptr = memreadline(ptr, buf, sizeof buf);
			if (*ptr != 0) {
				if (linenum <= 2) {
					/* skip the first two lines; they contain bogus filenames */
				}
				else {
					fprintf(fp, "%s\n", buf);
				}
			}
		} while ((*ptr != 0) && (ptr < ((char*)content + length)));
		if (pclose(fp) != 0) {
			syslog(LOG_ERR, "pclose() returned an error - patch failed\n");
		}
	}

	if (!strcasecmp(this_rev, hecbd->stop_when)) {
		/* Found our target rev.  Tell any subsequent callbacks to suppress processing. */
		syslog(LOG_DEBUG, "Target revision has been reached -- stop patching.\n");
		hecbd->done = 1;
	}
}
Beispiel #6
0
/*
 * Convert FN (Friendly Name) into N (Name)
 *
 * vname	Supplied friendly-name
 * n		Target buffer to store Name
 * vname_size	Size of buffer
 */
void vcard_fn_to_n(char *vname, char *n, size_t vname_size) {
	char lastname[256];
	char firstname[256];
	char middlename[256];
	char honorific_prefixes[256];
	char honorific_suffixes[256];
	char buf[256];

	safestrncpy(buf, n, sizeof buf);

	/* Try to intelligently convert the screen name to a
	 * fully expanded vCard name based on the number of
	 * words in the name
	 */
	safestrncpy(lastname, "", sizeof lastname);
	safestrncpy(firstname, "", sizeof firstname);
	safestrncpy(middlename, "", sizeof middlename);
	safestrncpy(honorific_prefixes, "", sizeof honorific_prefixes);
	safestrncpy(honorific_suffixes, "", sizeof honorific_suffixes);

	/* Honorific suffixes */
	if (num_tokens(buf, ',') > 1) {
		extract_token(honorific_suffixes, buf, (num_tokens(buf, ' ') - 1), ',',
			sizeof honorific_suffixes);
		remove_token(buf, (num_tokens(buf, ',') - 1), ',');
	}

	/* Find a last name */
	extract_token(lastname, buf, (num_tokens(buf, ' ') - 1), ' ', sizeof lastname);
	remove_token(buf, (num_tokens(buf, ' ') - 1), ' ');

	/* Find honorific prefixes */
	if (num_tokens(buf, ' ') > 2) {
		extract_token(honorific_prefixes, buf, 0, ' ', sizeof honorific_prefixes);
		remove_token(buf, 0, ' ');
	}

	/* Find a middle name */
	if (num_tokens(buf, ' ') > 1) {
		extract_token(middlename, buf, (num_tokens(buf, ' ') - 1), ' ', sizeof middlename);
		remove_token(buf, (num_tokens(buf, ' ') - 1), ' ');
	}

	/* Anything left is probably the first name */
	safestrncpy(firstname, buf, sizeof firstname);
	striplt(firstname);

	/* Compose the structured name */
	snprintf(vname, vname_size, "%s;%s;%s;%s;%s", lastname, firstname, middlename,
		honorific_prefixes, honorific_suffixes);
}
Beispiel #7
0
/*
 * Check to see if a META tag has overridden the declared MIME character set.
 *
 * charset		Character set name (left unchanged if we don't do anything)
 * meta_http_equiv	Content of the "http-equiv" portion of the META tag
 * meta_content		Content of the "content" portion of the META tag
 */
void extract_charset_from_meta(char *charset, char *meta_http_equiv, char *meta_content)
{
	char *ptr;
	char buf[64];

	if (!charset) return;
	if (!meta_http_equiv) return;
	if (!meta_content) return;


	if (strcasecmp(meta_http_equiv, "Content-type")) return;

	ptr = strchr(meta_content, ';');
	if (!ptr) return;

	safestrncpy(buf, ++ptr, sizeof buf);
	striplt(buf);
	if (!strncasecmp(buf, "charset=", 8)) {
		strcpy(charset, &buf[8]);

		/*
		 * The brain-damaged webmail program in Microsoft Exchange declares
		 * a charset of "unicode" when they really mean "UTF-8".  GNU iconv
		 * treats "unicode" as an alias for "UTF-16" so we have to manually
		 * fix this here, otherwise messages generated in Exchange webmail
		 * show up as a big pile of weird characters.
		 */
		if (!strcasecmp(charset, "unicode")) {
			strcpy(charset, "UTF-8");
		}

		/* Remove wandering punctuation */
		if ((ptr=strchr(charset, '\"'))) *ptr = 0;
		striplt(charset);
	}
}
/* Return nonzero if the supplied address is in a domain we keep in
 * the directory
 */
int IsDirectory(char *addr, int allow_masq_domains) {
	char domain[256];
	int h;

	extract_token(domain, addr, 1, '@', sizeof domain);
	striplt(domain);

	h = CtdlHostAlias(domain);

	if ( (h == hostalias_masq) && allow_masq_domains)
		return(1);
	
	if ( (h == hostalias_localhost) || (h == hostalias_directory) ) {
		return(1);
	}
	else {
		return(0);
	}
}
Beispiel #9
0
/*
 * Remove the "charset=" attribute from a vCard property name
 *
 */
void remove_charset_attribute(char *strbuf)
{
	int i, t;
	char compare[256];

	t = num_tokens(strbuf, ';');
	for (i=0; i<t; ++i) {
		extract_token(compare, strbuf, i, ';', sizeof compare);
		striplt(compare);
		if (!strncasecmp(compare, "charset=", 8)) {
			remove_token(strbuf, i, ';');
		}
	}
	if (!IsEmptyStr(strbuf)) {
		if (strbuf[strlen(strbuf)-1] == ';') {
			strbuf[strlen(strbuf)-1] = 0;
		}
	}
}
Beispiel #10
0
/*
 * Convert a structured name into a friendly name.  Caller must free the
 * returned pointer.
 */
char *n_to_fn(char *value) {
	char *nnn = NULL;
	int i;

	nnn = malloc(strlen(value) + 10);
	strcpy(nnn, "");
	extract_token(&nnn[strlen(nnn)] , value, 3, ';', 999);
	strcat(nnn, " ");
	extract_token(&nnn[strlen(nnn)] , value, 1, ';', 999);
	strcat(nnn, " ");
	extract_token(&nnn[strlen(nnn)] , value, 2, ';', 999);
	strcat(nnn, " ");
	extract_token(&nnn[strlen(nnn)] , value, 0, ';', 999);
	strcat(nnn, " ");
	extract_token(&nnn[strlen(nnn)] , value, 4, ';', 999);
	strcat(nnn, " ");
	for (i=0; i<strlen(nnn); ++i) {
		if (!strncmp(&nnn[i], "  ", 2)) strcpy(&nnn[i], &nnn[i+1]);
	}
	striplt(nnn);
	return(nnn);
}
Beispiel #11
0
/*
 * Before allowing a wiki page save to execute, we have to perform version control.
 * This involves fetching the old version of the page if it exists.
 */
int wiki_upload_beforesave(struct CtdlMessage *msg, recptypes *recp) {
	struct CitContext *CCC = CC;
	long old_msgnum = (-1L);
	struct CtdlMessage *old_msg = NULL;
	long history_msgnum = (-1L);
	struct CtdlMessage *history_msg = NULL;
	char diff_old_filename[PATH_MAX];
	char diff_new_filename[PATH_MAX];
	char diff_out_filename[PATH_MAX];
	char diff_cmd[PATH_MAX];
	FILE *fp;
	int rv;
	char history_page[1024];
	long history_page_len;
	char boundary[256];
	char prefixed_boundary[258];
	char buf[1024];
	char *diffbuf = NULL;
	size_t diffbuf_len = 0;
	char *ptr = NULL;
	long newmsgid;
	StrBuf *msgidbuf;

	if (!CCC->logged_in) return(0);	/* Only do this if logged in. */

	/* Is this a room with a Wiki in it, don't run this hook. */
	if ((CCC->room.QRdefaultview != VIEW_WIKI) &&
	    (CCC->room.QRdefaultview != VIEW_WIKIMD)) {
		return(0);
	}

	/* If this isn't a MIME message, don't bother. */
	if (msg->cm_format_type != 4) return(0);

	/* If there's no EUID we can't do this.  Reject the post. */
	if (CM_IsEmpty(msg, eExclusiveID)) return(1);

	newmsgid = get_new_message_number();
	msgidbuf = NewStrBuf();
	StrBufPrintf(msgidbuf, "%08lX-%08lX@%s/%s",
		     (long unsigned int) time(NULL),
		     (long unsigned int) newmsgid,
		     CtdlGetConfigStr("c_fqdn"),
		     msg->cm_fields[eExclusiveID]
		);

	CM_SetAsFieldSB(msg, emessageId, &msgidbuf);

	history_page_len = snprintf(history_page, sizeof history_page,
				    "%s_HISTORY_", msg->cm_fields[eExclusiveID]);

	/* Make sure we're saving a real wiki page rather than a wiki history page.
	 * This is important in order to avoid recursing infinitely into this hook.
	 */
	if (	(msg->cm_lengths[eExclusiveID] >= 9)
		&& (!strcasecmp(&msg->cm_fields[eExclusiveID][msg->cm_lengths[eExclusiveID]-9], "_HISTORY_"))
	) {
		syslog(LOG_DEBUG, "History page not being historied\n");
		return(0);
	}

	/* If there's no message text, obviously this is all b0rken and shouldn't happen at all */
	if (CM_IsEmpty(msg, eMesageText)) return(0);

	/* Set the message subject identical to the page name */
	CM_CopyField(msg, eMsgSubject, eExclusiveID);

	/* See if we can retrieve the previous version. */
	old_msgnum = CtdlLocateMessageByEuid(msg->cm_fields[eExclusiveID], &CCC->room);
	if (old_msgnum > 0L) {
		old_msg = CtdlFetchMessage(old_msgnum, 1, 1);
	}
	else {
		old_msg = NULL;
	}

	if ((old_msg != NULL) && (CM_IsEmpty(old_msg, eMesageText))) {	/* old version is corrupt? */
		CM_Free(old_msg);
		old_msg = NULL;
	}
	
	/* If no changes were made, don't bother saving it again */
	if ((old_msg != NULL) && (!strcmp(msg->cm_fields[eMesageText], old_msg->cm_fields[eMesageText]))) {
		CM_Free(old_msg);
		return(1);
	}

	/*
	 * Generate diffs
	 */
	CtdlMakeTempFileName(diff_old_filename, sizeof diff_old_filename);
	CtdlMakeTempFileName(diff_new_filename, sizeof diff_new_filename);
	CtdlMakeTempFileName(diff_out_filename, sizeof diff_out_filename);

	if (old_msg != NULL) {
		fp = fopen(diff_old_filename, "w");
		rv = fwrite(old_msg->cm_fields[eMesageText], old_msg->cm_lengths[eMesageText], 1, fp);
		fclose(fp);
		CM_Free(old_msg);
	}

	fp = fopen(diff_new_filename, "w");
	rv = fwrite(msg->cm_fields[eMesageText], msg->cm_lengths[eMesageText], 1, fp);
	fclose(fp);

	snprintf(diff_cmd, sizeof diff_cmd,
		DIFF " -u %s %s >%s",
		diff_new_filename,
		((old_msg != NULL) ? diff_old_filename : "/dev/null"),
		diff_out_filename
	);
	syslog(LOG_DEBUG, "diff cmd: %s", diff_cmd);
	rv = system(diff_cmd);
	syslog(LOG_DEBUG, "diff cmd returned %d", rv);

	diffbuf_len = 0;
	diffbuf = NULL;
	fp = fopen(diff_out_filename, "r");
	if (fp == NULL) {
		fp = fopen("/dev/null", "r");
	}
	if (fp != NULL) {
		fseek(fp, 0L, SEEK_END);
		diffbuf_len = ftell(fp);
		fseek(fp, 0L, SEEK_SET);
		diffbuf = malloc(diffbuf_len + 1);
		fread(diffbuf, diffbuf_len, 1, fp);
		diffbuf[diffbuf_len] = '\0';
		fclose(fp);
	}

	syslog(LOG_DEBUG, "diff length is "SIZE_T_FMT" bytes", diffbuf_len);

	unlink(diff_old_filename);
	unlink(diff_new_filename);
	unlink(diff_out_filename);

	/* Determine whether this was a bogus (empty) edit */
	if ((diffbuf_len = 0) && (diffbuf != NULL)) {
		free(diffbuf);
		diffbuf = NULL;
	}
	if (diffbuf == NULL) {
		return(1);		/* No changes at all?  Abandon the post entirely! */
	}

	/* Now look for the existing edit history */

	history_msgnum = CtdlLocateMessageByEuid(history_page, &CCC->room);
	history_msg = NULL;
	if (history_msgnum > 0L) {
		history_msg = CtdlFetchMessage(history_msgnum, 1, 1);
	}

	/* Create a new history message if necessary */
	if (history_msg == NULL) {
		char *buf;
		long len;

		history_msg = malloc(sizeof(struct CtdlMessage));
		memset(history_msg, 0, sizeof(struct CtdlMessage));
		history_msg->cm_magic = CTDLMESSAGE_MAGIC;
		history_msg->cm_anon_type = MES_NORMAL;
		history_msg->cm_format_type = FMT_RFC822;
		CM_SetField(history_msg, eAuthor, HKEY("Citadel"));
		if (!IsEmptyStr(CCC->room.QRname)){
			CM_SetField(history_msg, eRecipient, CCC->room.QRname, strlen(CCC->room.QRname));
		}
		CM_SetField(history_msg, eExclusiveID, history_page, history_page_len);
		CM_SetField(history_msg, eMsgSubject, history_page, history_page_len);
		CM_SetField(history_msg, eSuppressIdx, HKEY("1")); /* suppress full text indexing */
		snprintf(boundary, sizeof boundary, "Citadel--Multipart--%04x--%08lx", getpid(), time(NULL));
		buf = (char*) malloc(1024);
		len = snprintf(buf, 1024,
			       "Content-type: multipart/mixed; boundary=\"%s\"\n\n"
			       "This is a Citadel wiki history encoded as multipart MIME.\n"
			       "Each part is comprised of a diff script representing one change set.\n"
			       "\n"
			       "--%s--\n",
			       boundary, boundary
		);
		CM_SetAsField(history_msg, eMesageText, &buf, len);
	}

	/* Update the history message (regardless of whether it's new or existing) */

	/* Remove the Message-ID from the old version of the history message.  This will cause a brand
	 * new one to be generated, avoiding an uninitentional hit of the loop zapper when we replicate.
	 */
	CM_FlushField(history_msg, emessageId);

	/* Figure out the boundary string.  We do this even when we generated the
	 * boundary string in the above code, just to be safe and consistent.
	 */
	*boundary = '\0';

	ptr = history_msg->cm_fields[eMesageText];
	do {
		ptr = memreadline(ptr, buf, sizeof buf);
		if (*ptr != 0) {
			striplt(buf);
			if (!IsEmptyStr(buf) && (!strncasecmp(buf, "Content-type:", 13))) {
				if (
					(bmstrcasestr(buf, "multipart") != NULL)
					&& (bmstrcasestr(buf, "boundary=") != NULL)
				) {
					safestrncpy(boundary, bmstrcasestr(buf, "\""), sizeof boundary);
					char *qu;
					qu = strchr(boundary, '\"');
					if (qu) {
						strcpy(boundary, ++qu);
					}
					qu = strchr(boundary, '\"');
					if (qu) {
						*qu = 0;
					}
				}
			}
		}
	} while ( (IsEmptyStr(boundary)) && (*ptr != 0) );

	/*
	 * Now look for the first boundary.  That is where we need to insert our fun.
	 */
	if (!IsEmptyStr(boundary)) {
		char *MsgText;
		long MsgTextLen;
		time_t Now = time(NULL);

		snprintf(prefixed_boundary, sizeof(prefixed_boundary), "--%s", boundary);
		
		CM_GetAsField(history_msg, eMesageText, &MsgText, &MsgTextLen);

		ptr = bmstrcasestr(MsgText, prefixed_boundary);
		if (ptr != NULL) {
			StrBuf *NewMsgText;
			char uuid[64];
			char memo[512];
			long memolen;
			char encoded_memo[1024];
			
			NewMsgText = NewStrBufPlain(NULL, MsgTextLen + diffbuf_len + 1024);

			generate_uuid(uuid);
			memolen = snprintf(memo, sizeof(memo), "%s|%ld|%s|%s", 
					   uuid,
					   Now,
					   CCC->user.fullname,
					   CtdlGetConfigStr("c_nodename"));

			memolen = CtdlEncodeBase64(encoded_memo, memo, memolen, 0);

			StrBufAppendBufPlain(NewMsgText, HKEY("--"), 0);
			StrBufAppendBufPlain(NewMsgText, boundary, -1, 0);
			StrBufAppendBufPlain(
				NewMsgText, 
				HKEY("\n"
				     "Content-type: text/plain\n"
				     "Content-Disposition: inline; filename=\""), 0);

			StrBufAppendBufPlain(NewMsgText, encoded_memo, memolen, 0);

			StrBufAppendBufPlain(
				NewMsgText, 
				HKEY("\"\n"
				     "Content-Transfer-Encoding: 8bit\n"
				     "\n"), 0);

			StrBufAppendBufPlain(NewMsgText, diffbuf, diffbuf_len, 0);
			StrBufAppendBufPlain(NewMsgText, HKEY("\n"), 0);

			StrBufAppendBufPlain(NewMsgText, ptr, MsgTextLen - (ptr - MsgText), 0);
			free(MsgText);
			CM_SetAsFieldSB(history_msg, eMesageText, &NewMsgText); 
		}
		else
		{
			CM_SetAsField(history_msg, eMesageText, &MsgText, MsgTextLen); 
		}

		CM_SetFieldLONG(history_msg, eTimestamp, Now);
	
		CtdlSubmitMsg(history_msg, NULL, "", 0);
	}
	else {
		syslog(LOG_ALERT, "Empty boundary string in history message.  No history!\n");
	}

	free(diffbuf);
	CM_Free(history_msg);
	return(0);
}
Beispiel #12
0
/*
 * 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;
}
Beispiel #13
0
/*
 * Harvest any email addresses that someone might want to have in their
 * "collected addresses" book.
 */
char *harvest_collected_addresses(struct CtdlMessage *msg) {
	char *coll = NULL;
	char addr[256];
	char user[256], node[256], name[256];
	int is_harvestable;
	int i, j, h;
	eMsgField field = 0;

	if (msg == NULL) return(NULL);

	is_harvestable = 1;
	strcpy(addr, "");	
	if (!CM_IsEmpty(msg, eAuthor)) {
		strcat(addr, msg->cm_fields[eAuthor]);
	}
	if (!CM_IsEmpty(msg, erFc822Addr)) {
		strcat(addr, " <");
		strcat(addr, msg->cm_fields[erFc822Addr]);
		strcat(addr, ">");
		if (IsDirectory(msg->cm_fields[erFc822Addr], 0)) {
			is_harvestable = 0;
		}
	}

	if (is_harvestable) {
		coll = strdup(addr);
	}
	else {
		coll = strdup("");
	}

	if (coll == NULL) return(NULL);

	/* Scan both the R (To) and Y (CC) fields */
	for (i = 0; i < 2; ++i) {
		if (i == 0) field = eRecipient;
		if (i == 1) field = eCarbonCopY;

		if (!CM_IsEmpty(msg, field)) {
			for (j=0; j<num_tokens(msg->cm_fields[field], ','); ++j) {
				extract_token(addr, msg->cm_fields[field], j, ',', sizeof addr);
				if (strstr(addr, "=?") != NULL)
					utf8ify_rfc822_string(addr);
				process_rfc822_addr(addr, user, node, name);
				h = CtdlHostAlias(node);
				if ( (h != hostalias_localhost) && (h != hostalias_directory) ) {
					coll = realloc(coll, strlen(coll) + strlen(addr) + 4);
					if (coll == NULL) return(NULL);
					if (!IsEmptyStr(coll)) {
						strcat(coll, ",");
					}
					striplt(addr);
					strcat(coll, addr);
				}
			}
		}
	}

	if (IsEmptyStr(coll)) {
		free(coll);
		return(NULL);
	}
	return(coll);
}
Beispiel #14
0
/*
 * Sanitize and enhance an HTML message for display.
 * Also convert weird character sets to UTF-8 if necessary.
 * Also fixup img src="cid:..." type inline images to fetch the image
 *
 */
void output_html(const char *supplied_charset, int treat_as_wiki, int msgnum, StrBuf *Source, StrBuf *Target) {
	char buf[SIZ];
	char *msg;
	char *ptr;
	char *msgstart;
	char *msgend;
	StrBuf *converted_msg;
	int buffer_length = 1;
	int line_length = 0;
	int content_length = 0;
	char new_window[SIZ];
	int brak = 0;
	int alevel = 0;
	int scriptlevel = 0;
	int script_start_pos = (-1);
	int i;
	int linklen;
	char charset[128];
	StrBuf *BodyArea = NULL;
#ifdef HAVE_ICONV
	iconv_t ic = (iconv_t)(-1) ;
	char *ibuf;                   /* Buffer of characters to be converted */
	char *obuf;                   /* Buffer for converted characters      */
	size_t ibuflen;               /* Length of input buffer               */
	size_t obuflen;               /* Length of output buffer              */
	char *osav;                   /* Saved pointer to output buffer       */
#endif
	if (Target == NULL)
		Target = WC->WBuf;

	safestrncpy(charset, supplied_charset, sizeof charset);
	msg = strdup("");
	sprintf(new_window, "<a target=\"%s\" href=", TARGET);

	if (Source == NULL) while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
		line_length = strlen(buf);
		buffer_length = content_length + line_length + 2;
		ptr = realloc(msg, buffer_length);
		if (ptr == NULL) {
			StrBufAppendPrintf(Target, "<b>");
			StrBufAppendPrintf(Target, _("realloc() error! couldn't get %d bytes: %s"),
					buffer_length + 1,
					strerror(errno));
			StrBufAppendPrintf(Target, "</b><br><br>\n");
			while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
				/** flush */
			}
			free(msg);
			return;
		}
		msg = ptr;
		strcpy(&msg[content_length], buf);
		content_length += line_length;
		strcpy(&msg[content_length], "\n");
		content_length += 1;
	}
	else {
		content_length = StrLength(Source);
		free(msg);
		msg = (char*) ChrPtr(Source);/* TODO: remove cast */
		buffer_length = content_length;
	}

	/** Do a first pass to isolate the message body */
	ptr = msg + 1;
	msgstart = msg;
	msgend = &msg[content_length];

	while (ptr < msgend) {

		/** Advance to next tag */
		ptr = strchr(ptr, '<');
		if ((ptr == NULL) || (ptr >= msgend)) break;
		++ptr;
		if ((ptr == NULL) || (ptr >= msgend)) break;

		/*
		 *  Look for META tags.  Some messages (particularly in
		 *  Asian locales) illegally declare a message's character
		 *  set in the HTML instead of in the MIME headers.  This
		 *  is wrong but we have to work around it anyway.
		 */
		if (!strncasecmp(ptr, "META", 4)) {

			char *meta_start;
			char *meta_end;
			int meta_length;
			char *meta;
			char *meta_http_equiv;
			char *meta_content;
			char *spaceptr;

			meta_start = &ptr[4];
			meta_end = strchr(ptr, '>');
			if ((meta_end != NULL) && (meta_end <= msgend)) {
				meta_length = meta_end - meta_start + 1;
				meta = malloc(meta_length + 1);
				safestrncpy(meta, meta_start, meta_length);
				meta[meta_length] = 0;
				striplt(meta);
				if (!strncasecmp(meta, "HTTP-EQUIV=", 11)) {
					meta_http_equiv = strdup(&meta[11]);
					spaceptr = strchr(meta_http_equiv, ' ');
					if (spaceptr != NULL) {
						*spaceptr = 0;
						meta_content = strdup(++spaceptr);
						if (!strncasecmp(meta_content, "content=", 8)) {
							strcpy(meta_content, &meta_content[8]);
							stripquotes(meta_http_equiv);
							stripquotes(meta_content);
							extract_charset_from_meta(charset,
									meta_http_equiv, meta_content);
						}
						free(meta_content);
					}
					free(meta_http_equiv);
				}
				free(meta);
			}
		}

		/*
		 * Any of these tags cause everything up to and including
		 * the tag to be removed.
		 */	
		if ( (!strncasecmp(ptr, "HTML", 4))
				||(!strncasecmp(ptr, "HEAD", 4))
				||(!strncasecmp(ptr, "/HEAD", 5))
				||(!strncasecmp(ptr, "BODY", 4)) ) {
			char *pBody = NULL;

			if (!strncasecmp(ptr, "BODY", 4)) {
				pBody = ptr;
			}
			ptr = strchr(ptr, '>');
			if ((ptr == NULL) || (ptr >= msgend)) break;
			if ((pBody != NULL) && (ptr - pBody > 4)) {
				char* src;
				char *cid_start, *cid_end;

				*ptr = '\0';
				pBody += 4; 
				while ((isspace(*pBody)) && (pBody < ptr))
					pBody ++;
				BodyArea = NewStrBufPlain(NULL,  ptr - pBody);

				if (pBody < ptr) {
					src = strstr(pBody, "cid:");
					if (src) {
						cid_start = src + 4;
						cid_end = cid_start;
						while ((*cid_end != '"') && 
								!isspace(*cid_end) &&
								(cid_end < ptr))
							cid_end ++;

						/* copy tag and attributes up to src="cid: */
						StrBufAppendBufPlain(BodyArea, pBody, src - pBody, 0);

						/* add in /webcit/mimepart/<msgno>/CID/ 
						   trailing / stops dumb URL filters getting excited */
						StrBufAppendPrintf(BodyArea,
								"/webcit/mimepart/%d/",msgnum);
						StrBufAppendBufPlain(BodyArea, cid_start, cid_end - cid_start, 0);

						if (ptr - cid_end > 0)
							StrBufAppendBufPlain(BodyArea, 
									cid_end + 1, 
									ptr - cid_end, 0);
					}
					else 
						StrBufAppendBufPlain(BodyArea, pBody, ptr - pBody, 0);
				}
				*ptr = '>';
			}
			++ptr;
			if ((ptr == NULL) || (ptr >= msgend)) break;
			msgstart = ptr;
		}

		/*
		 * Any of these tags cause everything including and following
		 * the tag to be removed.
		 */
		if ( (!strncasecmp(ptr, "/HTML", 5))
				||(!strncasecmp(ptr, "/BODY", 5)) ) {
			--ptr;
			msgend = ptr;
			strcpy(ptr, "");

		}

		++ptr;
	}
	if (msgstart > msg) {
		strcpy(msg, msgstart);
	}

	/* Now go through the message, parsing tags as necessary. */
	converted_msg = NewStrBufPlain(NULL, content_length + 8192);


	/** Convert foreign character sets to UTF-8 if necessary. */
#ifdef HAVE_ICONV
	if ( (strcasecmp(charset, "us-ascii"))
			&& (strcasecmp(charset, "UTF-8"))
			&& (strcasecmp(charset, ""))
	   ) {
		syslog(LOG_DEBUG, "Converting %s to UTF-8\n", charset);
		ctdl_iconv_open("UTF-8", charset, &ic);
		if (ic == (iconv_t)(-1) ) {
			syslog(LOG_WARNING, "%s:%d iconv_open() failed: %s\n",
					__FILE__, __LINE__, strerror(errno));
		}
	}
	if  (Source == NULL) {
		if (ic != (iconv_t)(-1) ) {
			ibuf = msg;
			ibuflen = content_length;
			obuflen = content_length + (content_length / 2) ;
			obuf = (char *) malloc(obuflen);
			osav = obuf;
			iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen);
			content_length = content_length + (content_length / 2) - obuflen;
			osav[content_length] = 0;
			free(msg);
			msg = osav;
			iconv_close(ic);
		}
	}
	else {
		if (ic != (iconv_t)(-1) ) {
			StrBuf *Buf = NewStrBufPlain(NULL, StrLength(Source) + 8096);;
			StrBufConvert(Source, Buf, &ic);
			FreeStrBuf(&Buf);
			iconv_close(ic);
			msg = (char*)ChrPtr(Source); /* TODO: get rid of this. */
		}
	}

#endif

	/*
	 *	At this point, the message has been stripped down to
	 *	only the content inside the <BODY></BODY> tags, and has
	 *	been converted to UTF-8 if it was originally in a foreign
	 *	character set.  The text is also guaranteed to be null
	 *	terminated now.
	 */

	if (converted_msg == NULL) {
		StrBufAppendPrintf(Target, "Error %d: %s<br>%s:%d", errno, strerror(errno), __FILE__, __LINE__);
		goto BAIL;
	}

	if (BodyArea != NULL) {
		StrBufAppendBufPlain(converted_msg, HKEY("<table "), 0);  
		StrBufAppendBuf(converted_msg, BodyArea, 0);
		StrBufAppendBufPlain(converted_msg, HKEY(" width=\"100%\"><tr><td>"), 0);
	}
	ptr = msg;
	msgend = strchr(msg, 0);
	while (ptr < msgend) {

		/** Try to sanitize the html of any rogue scripts */
		if (!strncasecmp(ptr, "<script", 7)) {
			if (scriptlevel == 0) {
				script_start_pos = StrLength(converted_msg);
			}
			++scriptlevel;
		}
		if (!strncasecmp(ptr, "</script", 8)) {
			--scriptlevel;
		}

		/**
		 * Change mailto: links to WebCit mail, by replacing the
		 * link with one that points back to our mail room.  Due to
		 * the way we parse URL's, it'll even handle mailto: links
		 * that have "?subject=" in them.
		 */
		if (!strncasecmp(ptr, "<a href=\"mailto:", 16)) {
			content_length += 64;
			StrBufAppendPrintf(converted_msg,
					"<a href=\"display_enter?force_room=_MAIL_?recp=");
			ptr = &ptr[16];
			++alevel;
			++brak;
		}
		/** Make external links open in a separate window */
		else if (!strncasecmp(ptr, "<a href=\"", 9)) {
			++alevel;
			++brak;
			if ( ((strchr(ptr, ':') < strchr(ptr, '/')))
					&&  ((strchr(ptr, '/') < strchr(ptr, '>'))) 
			   ) {
				/* open external links to new window */
				StrBufAppendPrintf(converted_msg, new_window);
				ptr = &ptr[8];
			}
			else if (
				(treat_as_wiki)
				&& (strncasecmp(ptr, "<a href=\"wiki?", 14))
				&& (strncasecmp(ptr, "<a href=\"dotgoto?", 17))
				&& (strncasecmp(ptr, "<a href=\"knrooms?", 17))
			) {
				content_length += 64;
				StrBufAppendPrintf(converted_msg, "<a href=\"wiki?go=");
				StrBufUrlescAppend(converted_msg, WC->CurRoom.name, NULL);
				StrBufAppendPrintf(converted_msg, "?page=");
				ptr = &ptr[9];
			}
			else {
				StrBufAppendPrintf(converted_msg, "<a href=\"");
				ptr = &ptr[9];
			}
		}
		/** Fixup <img src="cid:... ...> to fetch the mime part */
		else if (!strncasecmp(ptr, "<img ", 5)) {
			char *cid_start, *cid_end;
			char* tag_end=strchr(ptr,'>');
			char* src;
			/* FIXME - handle this situation (maybe someone opened an <img cid... 
			 * and then ended the message)
			 */
			if (!tag_end) {
				syslog(LOG_DEBUG, "tag_end is null and ptr is:\n");
				syslog(LOG_DEBUG, "%s\n", ptr);
				syslog(LOG_DEBUG, "Theoretical bytes remaining: %d\n", (int)(msgend - ptr));
			}

			src=strstr(ptr, "src=\"cid:");
			++brak;

			if (src
			    && isspace(*(src-1))
				&& tag_end
				&& (cid_start=strchr(src,':'))
				&& (cid_end=strchr(cid_start,'"'))
				&& (cid_end < tag_end)
			) {
				/* copy tag and attributes up to src="cid: */
				StrBufAppendBufPlain(converted_msg, ptr, src - ptr, 0);
				cid_start++;

				/* add in /webcit/mimepart/<msgno>/CID/ 
				   trailing / stops dumb URL filters getting excited */
				StrBufAppendPrintf(converted_msg,
						" src=\"/webcit/mimepart/%d/",msgnum);
				StrBufAppendBufPlain(converted_msg, cid_start, cid_end - cid_start, 0);
				StrBufAppendBufPlain(converted_msg, "/\"", -1, 0);

				ptr = cid_end+1;
			}
			StrBufAppendBufPlain(converted_msg, ptr, tag_end - ptr, 0);
			ptr = tag_end;
		}

		/**
		 * Turn anything that looks like a URL into a real link, as long
		 * as it's not inside a tag already
		 */
		else if ( (brak == 0) && (alevel == 0) &&
			  ( (!strncasecmp(ptr, "http://", 7)) ||
			    (!strncasecmp(ptr, "https://", 8)))) {
			/** Find the end of the link */
			int strlenptr;
			linklen = 0;
				
			strlenptr = strlen(ptr);
			for (i=0; i<=strlenptr; ++i) {
				if ((ptr[i]==0)
				    ||(isspace(ptr[i]))
				    ||(ptr[i]==10)
				    ||(ptr[i]==13)
				    ||(ptr[i]=='(')
				    ||(ptr[i]==')')
				    ||(ptr[i]=='<')
				    ||(ptr[i]=='>')
				    ||(ptr[i]=='[')
				    ||(ptr[i]==']')
				    ||(ptr[i]=='"')
				    ||(ptr[i]=='\'')
					) linklen = i;
				/* did s.b. send us an entity? */
				if (ptr[i] == '&') {
					if ((ptr[i+2] ==';') ||
					    (ptr[i+3] ==';') ||
					    (ptr[i+5] ==';') ||
					    (ptr[i+6] ==';') ||
					    (ptr[i+7] ==';'))
						linklen = i;
				}
				if (linklen > 0) break;
			}
			if (linklen > 0) {
				char *ltreviewptr;
				char *nbspreviewptr;
				char linkedchar;
				int len;
					
				len = linklen;
				linkedchar = ptr[len];
				ptr[len] = '\0';
				/* spot for some subject strings tinymce tends to give us. */
				ltreviewptr = strchr(ptr, '<');
				if (ltreviewptr != NULL) {
					*ltreviewptr = '\0';
					linklen = ltreviewptr - ptr;
				}

				nbspreviewptr = strstr(ptr, "&nbsp;");
				if (nbspreviewptr != NULL) {
					/* nbspreviewptr = '\0'; */
					linklen = nbspreviewptr - ptr;
				}
				if (ltreviewptr != 0)
					*ltreviewptr = '<';

				ptr[len] = linkedchar;

				content_length += (32 + linklen);
				StrBufAppendPrintf(converted_msg, "%s\"", new_window);
				StrBufAppendBufPlain(converted_msg, ptr, linklen, 0);
				StrBufAppendPrintf(converted_msg, "\">");
				StrBufAppendBufPlain(converted_msg, ptr, linklen, 0);
				ptr += linklen;
				StrBufAppendPrintf(converted_msg, "</A>");
			}
		}
		else {
			StrBufAppendBufPlain(converted_msg, ptr, 1, 0);
			ptr++;
		}


		if ((ptr >= msg) && (ptr <= msgend)) {
			/*
			 * We need to know when we're inside a tag,
			 * so we don't turn things that look like URL's into
			 * links, when they're already links - or image sources.
			 */
			if ((ptr > msg) && (*(ptr-1) == '<')) {
				++brak;
			}
			if ((ptr > msg) && (*(ptr-1) == '>')) {
				--brak;
				if ((scriptlevel == 0) && (script_start_pos >= 0)) {
					StrBufCutRight(converted_msg, StrLength(converted_msg) - script_start_pos);
					script_start_pos = (-1);
				}
			}
			if (!strncasecmp(ptr, "</A>", 3)) --alevel;
		}
	}

	if (BodyArea != NULL) {
		StrBufAppendBufPlain(converted_msg, HKEY("</td></tr></table>"), 0);  
		FreeStrBuf(&BodyArea);
	}

	/**	uncomment these two lines to override conversion	*/
	/**	memcpy(converted_msg, msg, content_length);		*/
	/**	output_length = content_length;				*/

	/** Output our big pile of markup */
	StrBufAppendBuf(Target, converted_msg, 0);

BAIL:	/** A little trailing vertical whitespace... */
	StrBufAppendPrintf(Target, "<br><br>\n");

	/** Now give back the memory */
	FreeStrBuf(&converted_msg);
	if ((msg != NULL) && (Source == NULL)) free(msg);
}
Beispiel #15
0
/*
 * Aliasing for network mail.
 * (Error messages have been commented out, because this is a server.)
 */
int alias(char *name)
{				/* process alias and routing info for mail */
	struct CitContext *CCC = CC;
	FILE *fp;
	int a, i;
	char aaa[SIZ], bbb[SIZ];
	char *ignetcfg = NULL;
	char *ignetmap = NULL;
	int at = 0;
	char node[64];
	char testnode[64];
	char buf[SIZ];

	char original_name[256];
	safestrncpy(original_name, name, sizeof original_name);

	striplt(name);
	remove_any_whitespace_to_the_left_or_right_of_at_symbol(name);
	stripallbut(name, '<', '>');

	fp = fopen(file_mail_aliases, "r");
	if (fp == NULL) {
		fp = fopen("/dev/null", "r");
	}
	if (fp == NULL) {
		return (MES_ERROR);
	}
	strcpy(aaa, "");
	strcpy(bbb, "");
	while (fgets(aaa, sizeof aaa, fp) != NULL) {
		while (isspace(name[0]))
			strcpy(name, &name[1]);
		aaa[strlen(aaa) - 1] = 0;
		strcpy(bbb, "");
		for (a = 0; aaa[a] != '\0'; ++a) {
			if (aaa[a] == ',') {
				strcpy(bbb, &aaa[a + 1]);
				aaa[a] = 0;
				break;
			}
		}
		if (!strcasecmp(name, aaa))
			strcpy(name, bbb);
	}
	fclose(fp);

	/* Hit the Global Address Book */
	if (CtdlDirectoryLookup(aaa, name, sizeof aaa) == 0) {
		strcpy(name, aaa);
	}

	if (strcasecmp(original_name, name)) {
		MSG_syslog(LOG_INFO, "%s is being forwarded to %s\n", original_name, name);
	}

	/* Change "user @ xxx" to "user" if xxx is an alias for this host */
	for (a=0; name[a] != '\0'; ++a) {
		if (name[a] == '@') {
			if (CtdlHostAlias(&name[a+1]) == hostalias_localhost) {
				name[a] = 0;
				MSG_syslog(LOG_INFO, "Changed to <%s>\n", name);
				break;
			}
		}
	}

	/* determine local or remote type, see citadel.h */
	at = haschar(name, '@');
	if (at == 0) return(MES_LOCAL);		/* no @'s - local address */
	if (at > 1) return(MES_ERROR);		/* >1 @'s - invalid address */
	remove_any_whitespace_to_the_left_or_right_of_at_symbol(name);

	/* figure out the delivery mode */
	extract_token(node, name, 1, '@', sizeof node);

	/* If there are one or more dots in the nodename, we assume that it
	 * is an FQDN and will attempt SMTP delivery to the Internet.
	 */
	if (haschar(node, '.') > 0) {
		return(MES_INTERNET);
	}

	/* Otherwise we look in the IGnet maps for a valid Citadel node.
	 * Try directly-connected nodes first...
	 */
	ignetcfg = CtdlGetSysConfig(IGNETCFG);
	for (i=0; i<num_tokens(ignetcfg, '\n'); ++i) {
		extract_token(buf, ignetcfg, i, '\n', sizeof buf);
		extract_token(testnode, buf, 0, '|', sizeof testnode);
		if (!strcasecmp(node, testnode)) {
			free(ignetcfg);
			return(MES_IGNET);
		}
	}
	free(ignetcfg);

	/*
	 * Then try nodes that are two or more hops away.
	 */
	ignetmap = CtdlGetSysConfig(IGNETMAP);
	for (i=0; i<num_tokens(ignetmap, '\n'); ++i) {
		extract_token(buf, ignetmap, i, '\n', sizeof buf);
		extract_token(testnode, buf, 0, '|', sizeof testnode);
		if (!strcasecmp(node, testnode)) {
			free(ignetmap);
			return(MES_IGNET);
		}
	}
	free(ignetmap);

	/* If we get to this point it's an invalid node name */
	return (MES_ERROR);
}
Beispiel #16
0
int smtp_resolve_recipients(SmtpOutMsg *Msg)
{
	AsyncIO *IO = &Msg->IO;
	const char *ptr;
	char buf[1024];
	int scan_done;
	int lp, rp;
	int i;

	EVNCS_syslog(LOG_DEBUG, "%s\n", __FUNCTION__);

	if ((Msg==NULL) ||
	    (Msg->MyQEntry == NULL) ||
	    (StrLength(Msg->MyQEntry->Recipient) == 0)) {
		return 0;
	}

	/* Parse out the host portion of the recipient address */
	process_rfc822_addr(ChrPtr(Msg->MyQEntry->Recipient),
			    Msg->user,
			    Msg->node,
			    Msg->name);

	EVNCS_syslog(LOG_DEBUG,
		     "Attempting delivery to <%s> @ <%s> (%s)\n",
		     Msg->user,
		     Msg->node,
		     Msg->name);

	/* If no envelope_from is supplied, extract one from the message */
	Msg->envelope_from = ChrPtr(Msg->MyQItem->EnvelopeFrom);
	if ( (Msg->envelope_from == NULL) ||
	     (IsEmptyStr(Msg->envelope_from)) ) {
		Msg->mailfrom[0] = '\0';
		scan_done = 0;
		ptr = ChrPtr(Msg->msgtext);
		do {
			if (ptr = cmemreadline(ptr, buf, sizeof buf), *ptr == 0)
			{
				scan_done = 1;
			}
			if (!strncasecmp(buf, "From:", 5))
			{
				safestrncpy(Msg->mailfrom,
					    &buf[5],
					    sizeof Msg->mailfrom);

				striplt(Msg->mailfrom);
				for (i=0; Msg->mailfrom[i]; ++i) {
					if (!isprint(Msg->mailfrom[i]))
					{
						strcpy(&Msg->mailfrom[i],
						       &Msg->mailfrom[i+1]);
						i=0;
					}
				}

				/* Strip out parenthesized names */
				lp = (-1);
				rp = (-1);
				for (i=0;
				     !IsEmptyStr(Msg->mailfrom + i);
				     ++i)
				{
					if (Msg->mailfrom[i] == '(') lp = i;
					if (Msg->mailfrom[i] == ')') rp = i;
				}
				if ((lp>0)&&(rp>lp))
				{
					strcpy(&Msg->mailfrom[lp-1],
					       &Msg->mailfrom[rp+1]);
				}

				/* Prefer brokketized names */
				lp = (-1);
				rp = (-1);
				for (i=0;
				     !IsEmptyStr(Msg->mailfrom + i);
				     ++i)
				{
					if (Msg->mailfrom[i] == '<') lp = i;
					if (Msg->mailfrom[i] == '>') rp = i;
				}
				if ( (lp>=0) && (rp>lp) ) {
					Msg->mailfrom[rp] = 0;
					memmove(Msg->mailfrom,
						&Msg->mailfrom[lp + 1],
						rp - lp);
				}

				scan_done = 1;
			}
		} while (scan_done == 0);
		if (IsEmptyStr(Msg->mailfrom))
			strcpy(Msg->mailfrom, "*****@*****.**");

		stripallbut(Msg->mailfrom, '<', '>');
		Msg->envelope_from = Msg->mailfrom;
	}

	return 1;
}
Beispiel #17
0
/*
 * Look up a user in the directory to see if this is an account that can be authenticated
 */
int CtdlTryUserLDAP(char *username,
		char *found_dn, int found_dn_size,
		char *fullname, int fullname_size,
		uid_t *uid, int lookup_based_on_username)
{
	LDAP *ldserver = NULL;
	int i;
	LDAPMessage *search_result = NULL;
	LDAPMessage *entry = NULL;
	char searchstring[1024];
	struct timeval tv;
	char **values;
	char *user_dn = NULL;

	if (fullname) safestrncpy(fullname, username, fullname_size);

	if (ctdl_ldap_initialize(&ldserver) != LDAP_SUCCESS) {
		return(errno);
	}

	ldap_set_option(ldserver, LDAP_OPT_PROTOCOL_VERSION, &ctdl_require_ldap_version);
	ldap_set_option(ldserver, LDAP_OPT_REFERRALS, (void *)LDAP_OPT_OFF);

	striplt(config.c_ldap_bind_dn);
	striplt(config.c_ldap_bind_pw);
	syslog(LOG_DEBUG, "LDAP bind DN: %s", config.c_ldap_bind_dn);
	i = ldap_simple_bind_s(ldserver,
		(!IsEmptyStr(config.c_ldap_bind_dn) ? config.c_ldap_bind_dn : NULL),
		(!IsEmptyStr(config.c_ldap_bind_pw) ? config.c_ldap_bind_pw : NULL)
	);
	if (i != LDAP_SUCCESS) {
		syslog(LOG_ALERT, "LDAP: Cannot bind: %s (%d)", ldap_err2string(i), i);
		return(i);
	}

	tv.tv_sec = 10;
	tv.tv_usec = 0;

	if (config.c_auth_mode == AUTHMODE_LDAP_AD) {
		if (lookup_based_on_username != 0)
			snprintf(searchstring, sizeof(searchstring), "(displayName=%s)",username);
		else
			snprintf(searchstring, sizeof(searchstring), "(sAMAccountName=%s)", username);
	}
	else {
		if (lookup_based_on_username != 0)
			snprintf(searchstring, sizeof(searchstring), "(cn=%s)",username);
		else
			snprintf(searchstring, sizeof(searchstring), "(&(objectclass=posixAccount)(uid=%s))", username);
	}

	syslog(LOG_DEBUG, "LDAP search: %s", searchstring);
	(void) ldap_search_ext_s(
		ldserver,					/* ld				*/
		config.c_ldap_base_dn,				/* base				*/
		LDAP_SCOPE_SUBTREE,				/* scope			*/
		searchstring,					/* filter			*/
		NULL,						/* attrs (all attributes)	*/
		0,						/* attrsonly (attrs + values)	*/
		NULL,						/* serverctrls (none)		*/
		NULL,						/* clientctrls (none)		*/
		&tv,						/* timeout			*/
		1,						/* sizelimit (1 result max)	*/
		&search_result					/* res				*/
	);

	/* Ignore the return value of ldap_search_ext_s().  Sometimes it returns an error even when
	 * the search succeeds.  Instead, we check to see whether search_result is still NULL.
	 */
	if (search_result == NULL) {
		syslog(LOG_DEBUG, "LDAP search: zero results were returned");
		ldap_unbind(ldserver);
		return(2);
	}

	/* At this point we've got at least one result from our query.  If there are multiple
	 * results, we still only look at the first one.
	 */
	entry = ldap_first_entry(ldserver, search_result);
	if (entry) {

		user_dn = ldap_get_dn(ldserver, entry);
		if (user_dn) {
			syslog(LOG_DEBUG, "dn = %s", user_dn);
		}

		if (config.c_auth_mode == AUTHMODE_LDAP_AD) {
			values = ldap_get_values(ldserver, search_result, "displayName");
			if (values) {
				if (values[0]) {
					if (fullname) safestrncpy(fullname, values[0], fullname_size);
					syslog(LOG_DEBUG, "displayName = %s", values[0]);
				}
				ldap_value_free(values);
			}
		}
		else {
			values = ldap_get_values(ldserver, search_result, "cn");
			if (values) {
				if (values[0]) {
					if (fullname) safestrncpy(fullname, values[0], fullname_size);
					syslog(LOG_DEBUG, "cn = %s", values[0]);
				}
				ldap_value_free(values);
			}
		}
		/* If we know the username is the CN/displayName, we already set the uid*/
		if (lookup_based_on_username==0) {
			if (config.c_auth_mode == AUTHMODE_LDAP_AD) {
				values = ldap_get_values(ldserver, search_result, "objectGUID");
				if (values) {
					if (values[0]) {
						if (uid != NULL) {
							*uid = abs(HashLittle(values[0], strlen(values[0])));
							syslog(LOG_DEBUG, "uid hashed from objectGUID = %d", *uid);
						}
					}
					ldap_value_free(values);
				}
			}
			else {
				values = ldap_get_values(ldserver, search_result, "uidNumber");
				if (values) {
					if (values[0]) {
						syslog(LOG_DEBUG, "uidNumber = %s", values[0]);
						if (uid != NULL) {
							*uid = atoi(values[0]);
						}
					}
					ldap_value_free(values);
				}
			}
		}

	}

	/* free the results */
	ldap_msgfree(search_result);

	/* unbind so we can go back in as the authenticating user */
	ldap_unbind(ldserver);

	if (!user_dn) {
		syslog(LOG_DEBUG, "No such user was found.");
		return(4);
	}

	if (found_dn) safestrncpy(found_dn, user_dn, found_dn_size);
	ldap_memfree(user_dn);
	return(0);
}
Beispiel #18
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()
 */
recptypes *validate_recipients(const char *supplied_recipients, 
			       const char *RemoteIdentifier, 
			       int Flags) {
	struct CitContext *CCC = CC;
	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 = (recptypes *) malloc(sizeof(recptypes));
	if (ret == NULL) return(NULL);

	/* Set all strings to null and numeric values to zero */
	memset(ret, 0, sizeof(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, CtdlGetConfigStr("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);
}
Beispiel #19
0
int main(int argc, char **argv) {
	char buf[1024];
	char fromline[1024];
	FILE *fp;
	int i;
	struct passwd *pw;
	int from_header = 0;
	int in_body = 0;
	int relh=0;
	int home=0;
	char relhome[PATH_MAX]="";
	char ctdldir[PATH_MAX]=CTDLDIR;
	char *sp, *ep;
	char hostname[256];
	char **recipients = NULL;
	int num_recipients = 0;
	int to_or_cc = 0;
	int read_recipients_from_headers = 0;
	char *add_these_recipients = NULL;

	for (i=1; i<argc; ++i) {
		if (!strcmp(argv[i], "-d")) {
			debug = 1;
		}
		else if (!strcmp(argv[i], "-t")) {
			read_recipients_from_headers = 1;
		}
		else if (argv[i][0] != '-') {
			++num_recipients;
			recipients = realloc(recipients, (num_recipients * sizeof (char *)));
			recipients[num_recipients - 1] = strdup(argv[i]);
		}
	}
	       
	/* TODO: should we be able to calculate relative dirs? */
	calc_dirs_n_files(relh, home, relhome, ctdldir, 0);

	pw = getpwuid(getuid());

	fp = tmpfile();
	if (fp == NULL) return(errno);
	serv_sock = uds_connectsock(file_lmtp_socket);	/* FIXME: if called as 'sendmail' connect to file_lmtp_unfiltered_socket */
	serv_gets(buf);
	if (buf[0] != '2') {
		fprintf(stderr, "%s\n", &buf[4]);
		if (debug) fprintf(stderr, "citmail: could not connect to LMTP socket.\n");
		cleanup(1);
	}

	sp = strchr (buf, ' ');
	if (sp == NULL) {
		if (debug) fprintf(stderr, "citmail: could not calculate hostname.\n");
		cleanup(2);
	}
	sp ++;
	ep = strchr (sp, ' ');
	if (ep == NULL) {
		if (debug) fprintf(stderr, "citmail: error parsing hostname\n");
		cleanup(3);
	}
	else
		*ep = '\0';

	strncpy(hostname, sp, sizeof hostname);

	snprintf(fromline, sizeof fromline, "From: %s@%s", pw->pw_name, hostname);
	while (fgets(buf, 1024, stdin) != NULL) {
		if ( ( (buf[0] == 13) || (buf[0] == 10)) && (in_body == 0) ) {
			in_body = 1;
			if (from_header == 0) {
				fprintf(fp, "%s%s", fromline, buf);
			}
		}
		if (in_body == 0 && !strncasecmp(buf, "From:", 5)) {
			strcpy(fromline, buf);
			from_header = 1;
		}

		if (read_recipients_from_headers) {
			add_these_recipients = NULL;
			if ((isspace(buf[0])) && (to_or_cc)) {
				add_these_recipients = buf;
			}
			else {
				if ((!strncasecmp(buf, "To:", 3)) || (!strncasecmp(buf, "Cc:", 3))) {
					to_or_cc = 1;
				}
				else {
					to_or_cc = 0;
				}
				if (to_or_cc) {
					add_these_recipients = &buf[3];
				}
			}

			if (add_these_recipients) {
				int num_recp_on_this_line;
				char this_recp[256];

				num_recp_on_this_line = num_tokens(add_these_recipients, ',');
				for (i=0; i<num_recp_on_this_line; ++i) {
					extract_token(this_recp, add_these_recipients,
						i, ',', sizeof this_recp);
					striplt(this_recp);
					if (!IsEmptyStr(this_recp)) {
						++num_recipients;
						recipients = realloc(recipients,
							(num_recipients * sizeof (char *)));
						recipients[num_recipients - 1] = strdup(this_recp);
					}
				}
			}
		}

		fprintf(fp, "%s", buf);
	}
	strip_trailing_nonprint(fromline);

	sprintf(buf, "LHLO %s", hostname);
	serv_puts(buf);
	do {
		serv_gets(buf);
		strcat(buf, "    ");
	} while (buf[3] == '-');
	if (buf[0] != '2') {
		if (debug) fprintf(stderr, "citmail: LHLO command failed\n");
		cleanup(4);
	}

	snprintf(buf, sizeof buf, "MAIL %s", fromline);
	serv_puts(buf);
	serv_gets(buf);
	if (buf[0] != '2') {
		if (debug) fprintf(stderr, "citmail: MAIL command failed\n");
		cleanup(5);
	}

	for (i=0; i<num_recipients; ++i) {
		snprintf(buf, sizeof buf, "RCPT To: %s", recipients[i]);
		serv_puts(buf);
		serv_gets(buf);
		free(recipients[i]);
	}
	free(recipients);

	serv_puts("DATA");
	serv_gets(buf);
	if (buf[0]!='3') {
		if (debug) fprintf(stderr, "citmail: DATA command failed\n");
		cleanup(6);
	}

	rewind(fp);
	while (fgets(buf, sizeof buf, fp) != NULL) {
		strip_trailing_nonprint(buf);
		serv_puts(buf);
	}
	serv_puts(".");
	serv_gets(buf);
	if (buf[0] != '2') {
		fprintf(stderr, "%s\n", &buf[4]);
		cleanup(7);
	}
	else {
		cleanup(0);
	}

	/* We won't actually reach this statement but the compiler will
	 * display a spurious warning about an invalid return type if
	 * we don't return an int.
	 */
	return(0);
}
Beispiel #20
0
/*
 * Fetch a message from the server and extract a vNote from it
 */
struct vnote *vnote_new_from_msg(long msgnum,int unread) 
{
	StrBuf *Buf;
	StrBuf *Data = NULL;
	const char *bptr;
	int Done = 0;
	char uid_from_headers[256];
	char mime_partnum[256];
	char mime_filename[256];
	char mime_content_type[256];
	char mime_disposition[256];
	char relevant_partnum[256];
	int phase = 0;				/* 0 = citadel headers, 1 = mime headers, 2 = body */
	char msg4_content_type[256] = "";
	char msg4_content_encoding[256] = "";
	int msg4_content_length = 0;
	struct vnote *vnote_from_body = NULL;
	int vnote_inline = 0;			/* 1 = MSG4 gave us a text/x-vnote top level */

	relevant_partnum[0] = '\0';
	serv_printf("MSG4 %ld", msgnum);	/* we need the mime headers */
	Buf = NewStrBuf();
	StrBuf_ServGetln(Buf);
	if (GetServerStatus(Buf, NULL) != 1) {
		FreeStrBuf (&Buf);
		return NULL;
	}
	while ((StrBuf_ServGetln(Buf)>=0) && !Done) {
		if ( (StrLength(Buf)==3) && 
		     !strcmp(ChrPtr(Buf), "000")) {
			Done = 1;
			break;
		}
		bptr = ChrPtr(Buf);
		switch (phase) {
		case 0:
			if (!strncasecmp(bptr, "exti=", 5)) {
				safestrncpy(uid_from_headers, &(ChrPtr(Buf)[5]), sizeof uid_from_headers);
			}
			else if (!strncasecmp(bptr, "part=", 5)) {
				extract_token(mime_filename, &bptr[5], 1, '|', sizeof mime_filename);
				extract_token(mime_partnum, &bptr[5], 2, '|', sizeof mime_partnum);
				extract_token(mime_disposition, &bptr[5], 3, '|', sizeof mime_disposition);
				extract_token(mime_content_type, &bptr[5], 4, '|', sizeof mime_content_type);

				if (!strcasecmp(mime_content_type, "text/vnote")) {
					strcpy(relevant_partnum, mime_partnum);
				}
			}
			else if ((phase == 0) && (!strncasecmp(bptr, "text", 4))) {
				phase = 1;
			}
		break;
		case 1:
			if (!IsEmptyStr(bptr)) {
				if (!strncasecmp(bptr, "Content-type: ", 14)) {
					safestrncpy(msg4_content_type, &bptr[14], sizeof msg4_content_type);
					striplt(msg4_content_type);
				}
				else if (!strncasecmp(bptr, "Content-transfer-encoding: ", 27)) {
					safestrncpy(msg4_content_encoding, &bptr[27], sizeof msg4_content_encoding);
					striplt(msg4_content_type);
				}
				else if ((!strncasecmp(bptr, "Content-length: ", 16))) {
					msg4_content_length = atoi(&bptr[16]);
				}
				break;
			}
			else {
				phase++;
				if ((msg4_content_length > 0)
				    && ( !strcasecmp(msg4_content_encoding, "7bit"))
				    && (!strcasecmp(msg4_content_type, "text/vnote"))
				) { 
					vnote_inline = 1;
				}
			}
		case 2:
			if (vnote_inline) {
				Data = NewStrBufPlain(NULL, msg4_content_length * 2);
				if (msg4_content_length > 0) {
					StrBuf_ServGetBLOBBuffered(Data, msg4_content_length);
					phase ++;
				}
				else {
					StrBufAppendBuf(Data, Buf, 0);
					StrBufAppendBufPlain(Data, "\r\n", 1, 0);
				}
			}
		case 3:
			if (vnote_inline) {
				StrBufAppendBuf(Data, Buf, 0);
			}
		}
	}
	FreeStrBuf(&Buf);

	/* If MSG4 didn't give us the part we wanted, but we know that we can find it
	 * as one of the other MIME parts, attempt to load it now.
	 */
	if ((!vnote_inline) && (!IsEmptyStr(relevant_partnum))) {
		Data = load_mimepart(msgnum, relevant_partnum);
	}

	if (StrLength(Data) > 0) {
		if (IsEmptyStr(uid_from_headers)) {
			/* Convert an old-style note to a vNote */
			vnote_from_body = vnote_new();
			vnote_from_body->uid = strdup(uid_from_headers);
			vnote_from_body->color_red = pastel_palette[3][0];
			vnote_from_body->color_green = pastel_palette[3][1];
			vnote_from_body->color_blue = pastel_palette[3][2];
			vnote_from_body->body = malloc(StrLength(Data) + 1);
			vnote_from_body->body[0] = 0;
			memcpy(vnote_from_body->body, ChrPtr(Data), StrLength(Data) + 1);
			FreeStrBuf(&Data);
			return vnote_from_body;
		}
		else {
			char *Buf = SmashStrBuf(&Data);
			
			struct vnote *v = vnote_new_from_str(Buf);
			free(Buf);
			return(v);
		}
	}
	return NULL;
}
Beispiel #21
0
static long parse_MimeHeaders(interesting_mime_headers *m, 
			      char** pcontent_start, 
			      char *content_end)
{
	char buf[SIZ];
	char header[SIZ];
	long headerlen;
	char *ptr, *pch;
	int buflen = 0;
	int i;

	/* Learn interesting things from the headers */
	ptr = *pcontent_start;
	*header = '\0';
	headerlen = 0;
	do {
		ptr = memreadlinelen(ptr, buf, SIZ, &buflen);

		for (i = 0; i < buflen; ++i) {
			if (isspace(buf[i])) {
				buf[i] = ' ';
			}
		}

		if (!isspace(buf[0]) && (headerlen > 0)) {
			if (!strncasecmp(header, "Content-type:", 13)) {
				memcpy (m->b[content_type].Key, &header[13], headerlen - 12);
				m->b[content_type].Key[headerlen - 12] = '\0';
				m->b[content_type].len = striplt (m->b[content_type].Key);

				m->b[content_type_name].len = extract_key(m->b[content_type_name].Key, CKEY(m->b[content_type]), HKEY("name"), '=');
				m->b[charset].len           = extract_key(m->b[charset].Key,           CKEY(m->b[content_type]), HKEY("charset"), '=');
				m->b[boundary].len          = extract_key(m->b[boundary].Key,          header,       headerlen,  HKEY("boundary"), '=');

				/* Deal with weird headers */
				pch = strchr(m->b[content_type].Key, ' ');
				if (pch != NULL) {
					*pch = '\0';
					m->b[content_type].len = m->b[content_type].Key - pch;
				}
				pch = strchr(m->b[content_type].Key, ';');
				if (pch != NULL) {
					*pch = '\0';
					m->b[content_type].len = m->b[content_type].Key - pch;
				}
			}
			else if (!strncasecmp(header, "Content-Disposition:", 20)) {
				memcpy (m->b[disposition].Key, &header[20], headerlen - 19);
				m->b[disposition].Key[headerlen - 19] = '\0';
				m->b[disposition].len = striplt(m->b[disposition].Key);

				m->b[content_disposition_name].len = extract_key(m->b[content_disposition_name].Key, CKEY(m->b[disposition]), HKEY("name"), '=');
				m->b[filename].len                 = extract_key(m->b[filename].Key,                 CKEY(m->b[disposition]), HKEY("filename"), '=');
				pch = strchr(m->b[disposition].Key, ';');
				if (pch != NULL) *pch = '\0';
				m->b[disposition].len = striplt(m->b[disposition].Key);
			}
			else if (!strncasecmp(header, "Content-ID:", 11)) {
				memcpy(m->b[id].Key, &header[11], headerlen - 11);
				m->b[id].Key[headerlen - 11] = '\0';
				striplt(m->b[id].Key);
				m->b[id].len = stripallbut(m->b[id].Key, '<', '>');
			}
			else if (!strncasecmp(header, "Content-length: ", 15)) {
				char *clbuf;
				clbuf = &header[15];
				while (isspace(*clbuf))
					clbuf ++;
				m->content_length = (size_t) atol(clbuf);
			}
			else if (!strncasecmp(header, "Content-transfer-encoding: ", 26)) {
				memcpy(m->b[encoding].Key, &header[26], headerlen - 26);
				m->b[encoding].Key[headerlen - 26] = '\0';
				m->b[encoding].len = striplt(m->b[encoding].Key);
			}
			*header = '\0';
			headerlen = 0;
		}
		if ((headerlen + buflen + 2) < SIZ) {
			memcpy(&header[headerlen], buf, buflen);
			headerlen += buflen;
			header[headerlen] = '\0';
		}
		if (ptr >= content_end) {
			return -1;
		}
	} while ((!IsEmptyStr(buf)) && (*ptr != 0));

	m->is_multipart = m->b[boundary].len != 0;
	*pcontent_start = ptr;

	return 0;
}
Beispiel #22
0
/*
 * Learn LDAP attributes and stuff them into the vCard.
 * Returns nonzero if we changed anything.
 */
int Ctdl_LDAP_to_vCard(char *ldap_dn, struct vCard *v)
{
	int changed_something = 0;
	LDAP *ldserver = NULL;
	int i;
	struct timeval tv;
	LDAPMessage *search_result = NULL;
	LDAPMessage *entry = NULL;
	char **givenName;
	char **sn;
	char **cn;
	char **initials;
	char **o;
	char **street;
	char **l;
	char **st;
	char **postalCode;
	char **telephoneNumber;
	char **mobile;
	char **homePhone;
	char **facsimileTelephoneNumber;
	char **mail;
	char **uid;
	char **homeDirectory;
	char **uidNumber;
	char **loginShell;
	char **gidNumber;
	char **c;
	char **title;
	char **uuid;
	char *attrs[] = { "*","+",NULL};

	if (!ldap_dn) return(0);
	if (!v) return(0);

	if (ctdl_ldap_initialize(&ldserver) != LDAP_SUCCESS) {
		return(0);
	}

	ldap_set_option(ldserver, LDAP_OPT_PROTOCOL_VERSION, &ctdl_require_ldap_version);
	ldap_set_option(ldserver, LDAP_OPT_REFERRALS, (void *)LDAP_OPT_OFF);

	striplt(config.c_ldap_bind_dn);
	striplt(config.c_ldap_bind_pw);
	syslog(LOG_DEBUG, "LDAP bind DN: %s", config.c_ldap_bind_dn);
	i = ldap_simple_bind_s(ldserver,
		(!IsEmptyStr(config.c_ldap_bind_dn) ? config.c_ldap_bind_dn : NULL),
		(!IsEmptyStr(config.c_ldap_bind_pw) ? config.c_ldap_bind_pw : NULL)
	);
	if (i != LDAP_SUCCESS) {
		syslog(LOG_ALERT, "LDAP: Cannot bind: %s (%d)", ldap_err2string(i), i);
		return(0);
	}

	tv.tv_sec = 10;
	tv.tv_usec = 0;

	syslog(LOG_DEBUG, "LDAP search: %s", ldap_dn);
	(void) ldap_search_ext_s(
		ldserver,				/* ld				*/
		ldap_dn,				/* base				*/
		LDAP_SCOPE_SUBTREE,		/* scope			*/
		NULL,					/* filter			*/
		attrs,					/* attrs (all attributes)	*/
		0,						/* attrsonly (attrs + values)	*/
		NULL,					/* serverctrls (none)		*/
		NULL,					/* clientctrls (none)		*/
		&tv,					/* timeout			*/
		1,						/* sizelimit (1 result max)	*/
		&search_result			/* res				*/
	);
	
	/* Ignore the return value of ldap_search_ext_s().  Sometimes it returns an error even when
	 * the search succeeds.  Instead, we check to see whether search_result is still NULL.
	 */
	 
	if (search_result == NULL) {
		syslog(LOG_DEBUG, "LDAP search: zero results were returned");
		ldap_unbind(ldserver);
		return(0);
	}

	/* At this point we've got at least one result from our query.  If there are multiple
	 * results, we still only look at the first one.
	 */

	entry = ldap_first_entry(ldserver, search_result);
	if (entry) {
		syslog(LOG_DEBUG, "LDAP search, got user details for vcard.");
		givenName=ldap_get_values(ldserver, search_result, "givenName");
		sn=ldap_get_values(ldserver, search_result, "sn");
		cn=ldap_get_values(ldserver, search_result, "cn");
		initials=ldap_get_values(ldserver, search_result, "initials");
		title=ldap_get_values(ldserver, search_result, "title");
		o=ldap_get_values(ldserver, search_result, "o");
		street=ldap_get_values(ldserver, search_result, "street");
		l=ldap_get_values(ldserver, search_result, "l");
		st=ldap_get_values(ldserver, search_result, "st");
		postalCode=ldap_get_values(ldserver, search_result, "postalCode");
		telephoneNumber=ldap_get_values(ldserver, search_result, "telephoneNumber");
		mobile=ldap_get_values(ldserver, search_result, "mobile");
		homePhone=ldap_get_values(ldserver, search_result, "homePhone");
		facsimileTelephoneNumber=ldap_get_values(ldserver, search_result, "facsimileTelephoneNumber");
		mail=ldap_get_values(ldserver, search_result, "mail");
		uid=ldap_get_values(ldserver, search_result, "uid");
		homeDirectory=ldap_get_values(ldserver, search_result, "homeDirectory");
		uidNumber=ldap_get_values(ldserver, search_result, "uidNumber");
		loginShell=ldap_get_values(ldserver, search_result, "loginShell");
		gidNumber=ldap_get_values(ldserver, search_result, "gidNumber");
		c=ldap_get_values(ldserver, search_result, "c");
		uuid=ldap_get_values(ldserver, search_result, "entryUUID");

		if (street && l && st && postalCode && c) changed_something |= vcard_set_one_prop_iff_different(v,"adr",";;%s;%s;%s;%s;%s",street[0],l[0],st[0],postalCode[0],c[0]);
		if (telephoneNumber) changed_something |= vcard_set_one_prop_iff_different(v,"tel;work","%s",telephoneNumber[0]);
		if (facsimileTelephoneNumber) changed_something |= vcard_set_one_prop_iff_different(v,"tel;fax","%s",facsimileTelephoneNumber[0]);
		if (mobile) changed_something |= vcard_set_one_prop_iff_different(v,"tel;cell","%s",mobile[0]);
		if (homePhone) changed_something |= vcard_set_one_prop_iff_different(v,"tel;home","%s",homePhone[0]);
		if (givenName && sn) {
			if (initials) {
				changed_something |= vcard_set_one_prop_iff_different(v,"n","%s;%s;%s",sn[0],givenName[0],initials[0]);
			}
			else {
				changed_something |= vcard_set_one_prop_iff_different(v,"n","%s;%s",sn[0],givenName[0]);
			}
		}
		if (mail) {
			changed_something |= vcard_set_props_iff_different(v,"email;internet",ldap_count_values(mail),mail);
		}
		if (uuid) changed_something |= vcard_set_one_prop_iff_different(v,"X-uuid","%s",uuid[0]);
		if (o) changed_something |= vcard_set_one_prop_iff_different(v,"org","%s",o[0]);
		if (cn) changed_something |= vcard_set_one_prop_iff_different(v,"fn","%s",cn[0]);
		if (title) changed_something |= vcard_set_one_prop_iff_different(v,"title","%s",title[0]);
		
		if (givenName) ldap_value_free(givenName);
		if (initials) ldap_value_free(initials);
		if (sn) ldap_value_free(sn);
		if (cn) ldap_value_free(cn);
		if (o) ldap_value_free(o);
		if (street) ldap_value_free(street);
		if (l) ldap_value_free(l);
		if (st) ldap_value_free(st);
		if (postalCode) ldap_value_free(postalCode);
		if (telephoneNumber) ldap_value_free(telephoneNumber);
		if (mobile) ldap_value_free(mobile);
		if (homePhone) ldap_value_free(homePhone);
		if (facsimileTelephoneNumber) ldap_value_free(facsimileTelephoneNumber);
		if (mail) ldap_value_free(mail);
		if (uid) ldap_value_free(uid);
		if (homeDirectory) ldap_value_free(homeDirectory);
		if (uidNumber) ldap_value_free(uidNumber);
		if (loginShell) ldap_value_free(loginShell);
		if (gidNumber) ldap_value_free(gidNumber);
		if (c) ldap_value_free(c);
		if (title) ldap_value_free(title);
		if (uuid) ldap_value_free(uuid);
	}
	/* free the results */
	ldap_msgfree(search_result);

	/* unbind so we can go back in as the authenticating user */
	ldap_unbind(ldserver);
	
	return(changed_something);	/* tell the caller whether we made any changes */
}
Beispiel #23
0
/*
 * Split an RFC822-style address into userid, host, and full name
 *
 */
void process_rfc822_addr(const char *rfc822, char *user, char *node, char *name)
{
	int a;

	strcpy(user, "");
	strcpy(node, CtdlGetConfigStr("c_fqdn"));
	strcpy(name, "");

	if (rfc822 == NULL) return;

	/* extract full name - first, it's From minus <userid> */
	strcpy(name, rfc822);
	stripout(name, '<', '>');

	/* strip anything to the left of a bang */
	while ((!IsEmptyStr(name)) && (haschar(name, '!') > 0))
		strcpy(name, &name[1]);

	/* and anything to the right of a @ or % */
	for (a = 0; name[a] != '\0'; ++a) {
		if (name[a] == '@') {
			name[a] = 0;
			break;
		}
		if (name[a] == '%') {
			name[a] = 0;
			break;
		}
	}

	/* but if there are parentheses, that changes the rules... */
	if ((haschar(rfc822, '(') == 1) && (haschar(rfc822, ')') == 1)) {
		strcpy(name, rfc822);
		stripallbut(name, '(', ')');
	}

	/* but if there are a set of quotes, that supersedes everything */
	if (haschar(rfc822, 34) == 2) {
		strcpy(name, rfc822);
		while ((!IsEmptyStr(name)) && (name[0] != 34)) {
			strcpy(&name[0], &name[1]);
		}
		strcpy(&name[0], &name[1]);
		for (a = 0; name[a] != '\0'; ++a)
			if (name[a] == 34) {
				name[a] = 0;
				break;
			}
	}
	/* extract user id */
	strcpy(user, rfc822);

	/* first get rid of anything in parens */
	stripout(user, '(', ')');

	/* if there's a set of angle brackets, strip it down to that */
	if ((haschar(user, '<') == 1) && (haschar(user, '>') == 1)) {
		stripallbut(user, '<', '>');
	}

	/* strip anything to the left of a bang */
	while ((!IsEmptyStr(user)) && (haschar(user, '!') > 0))
		strcpy(user, &user[1]);

	/* and anything to the right of a @ or % */
	for (a = 0; user[a] != '\0'; ++a) {
		if (user[a] == '@') {
			user[a] = 0;
			break;
		}
		if (user[a] == '%') {
			user[a] = 0;
			break;
		}
	}


	/* extract node name */
	strcpy(node, rfc822);

	/* first get rid of anything in parens */
	stripout(node, '(', ')');

	/* if there's a set of angle brackets, strip it down to that */
	if ((haschar(node, '<') == 1) && (haschar(node, '>') == 1)) {
		stripallbut(node, '<', '>');
	}

	/* If no node specified, tack ours on instead */
	if (
		(haschar(node, '@')==0)
		&& (haschar(node, '%')==0)
		&& (haschar(node, '!')==0)
	) {
		strcpy(node, CtdlGetConfigStr("c_nodename"));
	}

	else {

		/* strip anything to the left of a @ */
		while ((!IsEmptyStr(node)) && (haschar(node, '@') > 0))
			strcpy(node, &node[1]);
	
		/* strip anything to the left of a % */
		while ((!IsEmptyStr(node)) && (haschar(node, '%') > 0))
			strcpy(node, &node[1]);
	
		/* reduce multiple system bang paths to node!user */
		while ((!IsEmptyStr(node)) && (haschar(node, '!') > 1))
			strcpy(node, &node[1]);
	
		/* now get rid of the user portion of a node!user string */
		for (a = 0; node[a] != '\0'; ++a)
			if (node[a] == '!') {
				node[a] = 0;
				break;
			}
	}

	/* strip leading and trailing spaces in all strings */
	striplt(user);
	striplt(node);
	striplt(name);

	/* If we processed a string that had the address in angle brackets
	 * but no name outside the brackets, we now have an empty name.  In
	 * this case, use the user portion of the address as the name.
	 */
	if ((IsEmptyStr(name)) && (!IsEmptyStr(user))) {
		strcpy(name, user);
	}
}