Beispiel #1
0
/*
 * MIME Parser callback for wiki_history()
 *
 * The "filename" field will contain a memo field.  All we have to do is decode
 * the base64 and output it.  The data is already in a delimited format suitable
 * for our client protocol.
 */
void wiki_history_callback(char *name, char *filename, char *partnum, char *disp,
		   void *content, char *cbtype, char *cbcharset, size_t length,
		   char *encoding, char *cbid, void *cbuserdata)
{
	char memo[1024];

	CtdlDecodeBase64(memo, filename, strlen(filename));
	cprintf("%s\n", memo);
}
Beispiel #2
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 #3
0
/*
 * this is the extract of mime_decode which can be called if 'dont_decode' was set; 
 * to save the cpu intense process of decoding to the time when it realy wants the content. 
 * returns: 
 *   - > 0 we decoded something, its on *decoded, you need to free it.
 *   - = 0 no need to decode stuff. *decoded will be NULL.
 *   - < 0 an error occured, either an unknown encoding, or alloc failed. no need to free.
 */
int mime_decode_now (char *part_start, 
		     size_t length,
		     char *encoding,
		     char **decoded,
		     size_t *bytes_decoded)
{
	*bytes_decoded = 0;
	*decoded = NULL;
	/* Some encodings aren't really encodings */
	if (!strcasecmp(encoding, "7bit"))
		*encoding = '\0';
	if (!strcasecmp(encoding, "8bit"))
		*encoding = '\0';
	if (!strcasecmp(encoding, "binary"))
		*encoding = '\0';

	/* If this part is not encoded, send as-is */
	if (strlen(encoding) == 0) {
		return 0;
	}
	

	/* Fail if we hit an unknown encoding. */
	if ((strcasecmp(encoding, "base64"))
	    && (strcasecmp(encoding, "quoted-printable"))) {
		return -1;
	}

	/*
	 * Allocate a buffer for the decoded data.  The output buffer is slightly
	 * larger than the input buffer; this assumes that the decoded data
	 * will never be significantly larger than the encoded data.  This is a
	 * safe assumption with base64, uuencode, and quoted-printable.
	 */
	*decoded = malloc(length + 32768);
	if (decoded == NULL) {
		return -1;
	}

	if (!strcasecmp(encoding, "base64")) {
		*bytes_decoded = CtdlDecodeBase64(*decoded, part_start, length);
		return 1;
	}
	else if (!strcasecmp(encoding, "quoted-printable")) {
		*bytes_decoded = CtdlDecodeQuotedPrintable(*decoded, part_start, length);
		return 1;
	}
	return -1;
}
Beispiel #4
0
/*
 * Set (or clear) stored passwords.
 */
void set_stored_password(
		char *host,
		char *port,
		char *username,
		char *password) {

	char pwfile[PATH_MAX];
	FILE *fp, *oldfp;
	char buf[SIZ];
	char buf64[SIZ];
	char hostbuf[256], portbuf[256], ubuf[256], pbuf[256];

	determine_pwfilename(pwfile, sizeof pwfile);
	if (IsEmptyStr(pwfile)) return;

	oldfp = fopen(pwfile, "r");
	if (oldfp == NULL) oldfp = fopen("/dev/null", "r");
	unlink(pwfile);
	fp = fopen(pwfile, "w");
	if (fp == NULL) fp = fopen("/dev/null", "w");
	while (fgets(buf64, sizeof buf64, oldfp) != NULL) {
		CtdlDecodeBase64(buf, buf64, sizeof(buf64));
		extract_token(hostbuf, buf, 0, '|', sizeof hostbuf);
		extract_token(portbuf, buf, 1, '|', sizeof portbuf);
		extract_token(ubuf, buf, 2, '|', sizeof ubuf);
		extract_token(pbuf, buf, 3, '|', sizeof pbuf);

		if ( (strcasecmp(hostbuf, host)) 
		   || (strcasecmp(portbuf, port)) ) {
			snprintf(buf, sizeof buf, "%s|%s|%s|%s|",
				hostbuf, portbuf, ubuf, pbuf);
			CtdlEncodeBase64(buf64, buf, strlen(buf), 0);
			fprintf(fp, "%s\n", buf64);
		}
	}
	if (!IsEmptyStr(username)) {
		snprintf(buf, sizeof buf, "%s|%s|%s|%s|",
			host, port, username, password);
		CtdlEncodeBase64(buf64, buf, strlen(buf), 0);
		fprintf(fp, "%s\n", buf64);
	}
	fclose(oldfp);
	fclose(fp);
	chmod(pwfile, 0600);
}
Beispiel #5
0
/*
 * Check the password file for a host/port match; if found, stuff the user
 * name and password into the user/pass buffers
 */
void get_stored_password(
		char *host,
		char *port,
		char *username,
		char *password) {

	char pwfile[PATH_MAX];
	FILE *fp;
	char buf[SIZ];
	char buf64[SIZ];
	char hostbuf[256], portbuf[256], ubuf[256], pbuf[256];

	strcpy(username, "");
	strcpy(password, "");

	determine_pwfilename(pwfile, sizeof pwfile);
	if (IsEmptyStr(pwfile)) return;

	fp = fopen(pwfile, "r");
	if (fp == NULL) return;
	while (fgets(buf64, sizeof buf64, fp) != NULL) {
		CtdlDecodeBase64(buf, buf64, sizeof(buf64));
		extract_token(hostbuf, buf, 0, '|', sizeof hostbuf);
		extract_token(portbuf, buf, 1, '|', sizeof portbuf);
		extract_token(ubuf, buf, 2, '|', sizeof ubuf);
		extract_token(pbuf, buf, 3, '|', sizeof pbuf);

		if (!strcasecmp(hostbuf, host)) {
			if (!strcasecmp(portbuf, port)) {
				strcpy(username, ubuf);
				strcpy(password, pbuf);
			}
		}
	}
	fclose(fp);
}
Beispiel #6
0
/*
 * Given a message or message-part body and a length, handle any necessary
 * decoding and pass the request up the stack.
 */
void mime_decode(char *partnum,
		 char *part_start, size_t length,
		 char *content_type, char *charset, char *encoding,
		 char *disposition,
		 char *id,
		 char *name, char *filename,
		 MimeParserCallBackType CallBack,
		 MimeParserCallBackType PreMultiPartCallBack,
		 MimeParserCallBackType PostMultiPartCallBack,
		 void *userdata,
		 int dont_decode)
{

	char *decoded;
	size_t bytes_decoded = 0;

	/* Some encodings aren't really encodings */
	if (!strcasecmp(encoding, "7bit"))
		*encoding = '\0';
	if (!strcasecmp(encoding, "8bit"))
		*encoding = '\0';
	if (!strcasecmp(encoding, "binary"))
		*encoding = '\0';
	if (!strcasecmp(encoding, "ISO-8859-1"))
		*encoding = '\0';

	/* If this part is not encoded, send as-is */
	if ( (strlen(encoding) == 0) || (dont_decode)) {
		if (CallBack != NULL) {
			CallBack(name, 
				 filename, 
				 fixed_partnum(partnum),
				 disposition, 
				 part_start,
				 content_type, 
				 charset, 
				 length, 
				 encoding, 
				 id,
				 userdata);
			}
		return;
	}
	
	/* Fail silently if we hit an unknown encoding. */
	if ((strcasecmp(encoding, "base64"))
	    && (strcasecmp(encoding, "quoted-printable"))) {
		return;
	}

	/*
	 * Allocate a buffer for the decoded data.  The output buffer is slightly
	 * larger than the input buffer; this assumes that the decoded data
	 * will never be significantly larger than the encoded data.  This is a
	 * safe assumption with base64, uuencode, and quoted-printable.
	 */
	decoded = malloc(length + 32768);
	if (decoded == NULL) {
		return;
	}

	if (!strcasecmp(encoding, "base64")) {
		bytes_decoded = CtdlDecodeBase64(decoded, part_start, length);
	}
	else if (!strcasecmp(encoding, "quoted-printable")) {
		bytes_decoded = CtdlDecodeQuotedPrintable(decoded, part_start, length);
	}

	if (bytes_decoded > 0) if (CallBack != NULL) {
			char encoding_buf[SIZ];

			strcpy(encoding_buf, "binary");
			CallBack(name, 
				 filename, 
				 fixed_partnum(partnum),
				 disposition, 
				 decoded,
				 content_type, 
				 charset, 
				 bytes_decoded, 
				 encoding_buf, 
				 id, 
				 userdata);
	}

	free(decoded);
}
/*
 * Handle subjects with RFC2047 encoding such as:
 * =?koi8-r?B?78bP0s3Mxc7JxSDXz9rE1dvO2c3JINvB0sHNySDP?=
 */
void utf8ify_rfc822_string(char *buf) {
	char *start, *end, *next, *nextend, *ptr;
	char newbuf[1024];
	char charset[128];
	char encoding[16];
	char istr[1024];
	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 *isav;			/**< Saved pointer to input buffer */
	char *osav;			/**< Saved pointer to output buffer */
	int passes = 0;
	int i, len, delta;
	int illegal_non_rfc2047_encoding = 0;

	/* Sometimes, badly formed messages contain strings which were simply
	 *  written out directly in some foreign character set instead of
	 *  using RFC2047 encoding.  This is illegal but we will attempt to
	 *  handle it anyway by converting from a user-specified default
	 *  charset to UTF-8 if we see any nonprintable characters.
	 */
	len = strlen(buf);
	for (i=0; i<len; ++i) {
		if ((buf[i] < 32) || (buf[i] > 126)) {
			illegal_non_rfc2047_encoding = 1;
			i = len; ///< take a shortcut, it won't be more than one.
		}
	}
	if (illegal_non_rfc2047_encoding) {
		const char *default_header_charset = "iso-8859-1";
		if ( (strcasecmp(default_header_charset, "UTF-8")) && (strcasecmp(default_header_charset, "us-ascii")) ) {
			ctdl_iconv_open("UTF-8", default_header_charset, &ic);
			if (ic != (iconv_t)(-1) ) {
				ibuf = malloc(1024);
				isav = ibuf;
				safestrncpy(ibuf, buf, 1024);
				ibuflen = strlen(ibuf);
				obuflen = 1024;
				obuf = (char *) malloc(obuflen);
				osav = obuf;
				iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen);
				osav[1024-obuflen] = 0;
				strcpy(buf, osav);
				free(osav);
				iconv_close(ic);
				free(isav);
			}
		}
	}

	/* pre evaluate the first pair */
	nextend = end = NULL;
	len = strlen(buf);
	start = strstr(buf, "=?");
	if (start != NULL) 
		FindNextEnd (start, end);

	while ((start != NULL) && (end != NULL))
	{
		next = strstr(end, "=?");
		if (next != NULL)
			FindNextEnd(next, nextend);
		if (nextend == NULL)
			next = NULL;

		/* did we find two partitions */
		if ((next != NULL) && 
		    ((next - end) > 2))
		{
			ptr = end + 2;
			while ((ptr < next) && 
			       (isspace(*ptr) ||
				(*ptr == '\r') ||
				(*ptr == '\n') || 
				(*ptr == '\t')))
				ptr ++;
			/* did we find a gab just filled with blanks? */
			if (ptr == next)
			{
				memmove (end + 2,
					 next,
					 len - (next - start));

				/* now terminate the gab at the end */
				delta = (next - end) - 2;
				len -= delta;
				buf[len] = '\0';

				/* move next to its new location. */
				next -= delta;
				nextend -= delta;
			}
		}
		/* our next-pair is our new first pair now. */
		start = next;
		end = nextend;
	}

	/* Now we handle foreign character sets properly encoded
	 * in RFC2047 format.
	 */
	start = strstr(buf, "=?");
	FindNextEnd((start != NULL)? start : buf, end);
	while (start != NULL && end != NULL && end > start)
	{
		extract_token(charset, start, 1, '?', sizeof charset);
		extract_token(encoding, start, 2, '?', sizeof encoding);
		extract_token(istr, start, 3, '?', sizeof istr);

		ibuf = malloc(1024);
		isav = ibuf;
		if (!strcasecmp(encoding, "B")) {	/**< base64 */
			ibuflen = CtdlDecodeBase64(ibuf, istr, strlen(istr));
		}
		else if (!strcasecmp(encoding, "Q")) {	/**< quoted-printable */
			size_t len;
			unsigned long pos;
			
			len = strlen(istr);
			pos = 0;
			while (pos < len)
			{
				if (istr[pos] == '_') istr[pos] = ' ';
				pos++;
			}

			ibuflen = CtdlDecodeQuotedPrintable(ibuf, istr, len);
		}
		else {
			strcpy(ibuf, istr);		/**< unknown encoding */
			ibuflen = strlen(istr);
		}

		ctdl_iconv_open("UTF-8", charset, &ic);
		if (ic != (iconv_t)(-1) ) {
			obuflen = 1024;
			obuf = (char *) malloc(obuflen);
			osav = obuf;
			iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen);
			osav[1024-obuflen] = 0;

			end = start;
			end++;
			strcpy(start, "");
			remove_token(end, 0, '?');
			remove_token(end, 0, '?');
			remove_token(end, 0, '?');
			remove_token(end, 0, '?');
			strcpy(end, &end[1]);

			snprintf(newbuf, sizeof newbuf, "%s%s%s", buf, osav, end);
			strcpy(buf, newbuf);
			free(osav);
			iconv_close(ic);
		}
		else {
			end = start;
			end++;
			strcpy(start, "");
			remove_token(end, 0, '?');
			remove_token(end, 0, '?');
			remove_token(end, 0, '?');
			remove_token(end, 0, '?');
			strcpy(end, &end[1]);

			snprintf(newbuf, sizeof newbuf, "%s(unreadable)%s", buf, end);
			strcpy(buf, newbuf);
		}

		free(isav);

		/*
		 * Since spammers will go to all sorts of absurd lengths to get their
		 * messages through, there are LOTS of corrupt headers out there.
		 * So, prevent a really badly formed RFC2047 header from throwing
		 * this function into an infinite loop.
		 */
		++passes;
		if (passes > 20) return;

		start = strstr(buf, "=?");
		FindNextEnd((start != NULL)? start : buf, end);
	}

}