Exemple #1
0
/**
 * All functions below are pretty self explanitory.  
 * They basically just preform some simple header printing 
 * for our email 'message'.  I'm not doing to comment every 
 * function from here because you should be able to read the 
 * damn functions and get a great idea
**/
static void
printMimeHeaders(const char *b, dstrbuf *msg, CharSetType charset)
{
	dsbPrintf(msg, "Mime-Version: 1.0\r\n");
	if (Mopts.gpg_opts & GPG_ENC) {
		dsbPrintf(msg, "Content-Type: multipart/encrypted; "
			"protocol=\"application/pgp-encrypted\"; " 
			"boundary=\"%s\"\r\n", b);
	} else if (Mopts.gpg_opts & GPG_SIG) {
		dsbPrintf(msg, "Content-Type: multipart/signed; "
			"micalg=pgp-sha1; protocol=\"application/pgp-signature\"; "
			"boundary=\"%s\"\r\n", b);
	} else if (Mopts.attach) {
		dsbPrintf(msg, "Content-Type: multipart/mixed; boundary=\"%s\"\r\n", b);
	} else {
		if (charset == IS_UTF8 || charset == IS_PARTIAL_UTF8) {
			dsbPrintf(msg, "Content-Type: text/plain; charset=utf-8\r\n");
			if (charset == IS_PARTIAL_UTF8) {
				dsbPrintf(msg, "Content-Transfer-Encoding: quoted-printable\r\n");
			} else {
				dsbPrintf(msg, "Content-Transfer-Encoding: base64\r\n");
			}
			dsbPrintf(msg, "Content-Disposition: inline\r\n");
		} else if (Mopts.html) {
			dsbPrintf(msg, "Content-Type: text/html\r\n");
		} else {
			dsbPrintf(msg, "Content-Type: text/plain\r\n");
		}
	}
}
Exemple #2
0
/**
 * This function takes the current content that was copied
 * in to us and creates a final message with the email header
 * and the appended content.  It will also attach any files
 * that were specified at the command line.
**/
static void
printHeaders(const char *border, dstrbuf *msg, CharSetType msg_cs)
{
	char *subject=Mopts.subject;
	char *user_name = getConfValue("MY_NAME");
	char *email_addr = getConfValue("MY_EMAIL");
	char *sm_bin = getConfValue("SENDMAIL_BIN");
	char *smtp_serv = getConfValue("SMTP_SERVER");
	char *reply_to = getConfValue("REPLY_TO");
	dstrbuf *dsb=NULL;

	if (subject) {
		if (Mopts.encoding) {
			CharSetType cs = getCharSet((u_char *)subject);
			if (cs == IS_UTF8) {
				dsb = encodeUtf8String((u_char *)subject, false);
				subject = dsb->str;
			} else if (cs == IS_PARTIAL_UTF8) {
				dsb = encodeUtf8String((u_char *)subject, true);
				subject = dsb->str;
			}
		}
		dsbPrintf(msg, "Subject: %s\r\n", subject);
		if (dsb) {
			dsbDestroy(dsb);
		}
	}
	printFromHeaders(user_name, email_addr, msg);
	printToHeaders(Mopts.to, Mopts.cc, msg);

	/**
	 * We want to check here to see if we are sending mail by invoking sendmail
	 * If so, We want to add the BCC line to the headers.  Sendmail checks this
	 * Line and makes sure it sends the mail to the BCC people, and then remove
	 * the BCC addresses...  Keep in mind that sending to an smtp servers takes
	 * presidence over sending to sendmail incase both are mentioned.
	 */
	if (sm_bin && !smtp_serv) {
		printBccHeaders(Mopts.bcc, msg);
	}

	/* The rest of the standard headers */
	printDateHeaders(msg);
	if (reply_to) {
		dsbPrintf(msg, "Reply-To: <%s>\r\n", reply_to);
	}
	printMimeHeaders(border, msg, msg_cs);
	dsbPrintf(msg, "X-Mailer: Cleancode.email v%s \r\n", EMAIL_VERSION);
	if (Mopts.priority) {
		dsbPrintf(msg, "X-Priority: 1\r\n");
	}
	printExtraHeaders(Mopts.headers, msg);
	dsbPrintf(msg, "\r\n");
}
Exemple #3
0
/**
 * just prints the to headers, and cc headers if available
**/
static void
printToHeaders(dlist to, dlist cc, dstrbuf *msg)
{
	struct addr *a = (struct addr *)dlGetNext(to);
	dsbPrintf(msg, "To: ");
	while (a) {
		dstrbuf *tmp = formatEmailAddr(a->name, a->email);
		dsbPrintf(msg, "%s", tmp->str);
		dsbDestroy(tmp);
		a = (struct addr *)dlGetNext(to);
		if (a != NULL) {
			dsbPrintf(msg, ", ");
		} else {
			dsbPrintf(msg, "\r\n");
		}
	}

	if (cc != NULL) {
		dsbPrintf(msg, "Cc: ");
		a = (struct addr *)dlGetNext(cc);
		while (a) {
			dstrbuf *tmp = formatEmailAddr(a->name, a->email);
			dsbPrintf(msg, "%s", tmp->str);
			dsbDestroy(tmp);
			a = (struct addr *)dlGetNext(cc);
			if (a != NULL) {
				dsbPrintf(msg, ", ");
			} else {
				dsbPrintf(msg, "\r\n");
			}
		}
	}
}
Exemple #4
0
/** Print From Headers **/
static void
printFromHeaders(char *name, char *address, dstrbuf *msg)
{
	dstrbuf *addr = formatEmailAddr(name, address);
	dsbPrintf(msg, "From: %s\r\n", addr->str);
	dsbDestroy(addr);
}
Exemple #5
0
static void
printExtraHeaders(dlist headers, dstrbuf *msg)
{
	char *hdr=NULL;
	while ((hdr = (char *)dlGetNext(headers)) != NULL) {
		dsbPrintf(msg, "%s\r\n", hdr);
	}
}
Exemple #6
0
/**
 * Makes a boundary for Mime emails 
**/
dstrbuf *
mimeMakeBoundary(void)
{
	dstrbuf *buf=DSB_NEW;
	dstrbuf *rstr=randomString(15);
	dsbPrintf(buf, "=-%s", rstr->str);
	return buf;
}
Exemple #7
0
/**
 * set up the appropriate MIME and Base64 headers for 
 * the attachment of file specified in Mopts.attach
**/
static int
attachFiles(const char *boundary, dstrbuf *out)
{
	dstrbuf *file_name = NULL;
	dstrbuf *file_type = NULL;
	char *next_file = NULL;

	/*
	* What we will do here is parse Mopts.attach for comma delimited file
	* names.  If there was only one file specified with no comma, then strtok()
	* will just return that file and the next call to strtok() will be NULL
	* which will allow use to break out of our loop of attaching base64 stuff.
	*/
	while ((next_file = (char *)dlGetNext(Mopts.attach)) != NULL) {
		FILE *current = fopen(next_file, "r");
		if (!current) {
			#if 1 //Ren: to skip nonexistent file
			fprintf(stderr, "email: skip %s\n", next_file);
			continue;
			#else
			fatal("Could not open attachment: %s", next_file);
			return (ERROR);
			#endif
		}

		/* If the user specified an absolute path, just get the file name */
		file_type = mimeFiletype(next_file);
		file_name = mimeFilename(next_file);

		/* Set our MIME headers */
		dsbPrintf(out, "\r\n--%s\r\n", boundary);
		dsbPrintf(out, "Content-Transfer-Encoding: base64\r\n");
		dsbPrintf(out, "Content-Type: %s; name=\"%s\"\r\n", 
			file_type->str, file_name->str);
		dsbPrintf(out, "Content-Disposition: attachment; filename=\"%s\"\r\n", 
			file_name->str);
		dsbPrintf(out, "\r\n");

		/* Encode to 'out' */
		mimeB64EncodeFile(current, out);
		dsbDestroy(file_type);
		dsbDestroy(file_name);
	}
	return SUCCESS;
}
Exemple #8
0
/**
 * Makes a message type specifically for gpg encryption and 
 * signing.  Specific MIME message descriptions are needed
 * when signing/encrypting a file before it is actuall signed
 * or encrypted.  This function takes care of that.
**/
static int
makeGpgMessage(dstrbuf *in, dstrbuf *out, const char *border)
{
	dstrbuf *qp=NULL;

	assert(in != NULL);
	assert(out != NULL);
	assert(border != NULL);

	if (Mopts.attach) {
		dsbPrintf(out, "Content-Type: multipart/mixed; "
			"boundary=\"%s\"\r\n\r\n", border);
		dsbPrintf(out, "\r\n--%s\r\n", border);
	}

	if (Mopts.html) {
		dsbPrintf(out, "Content-Type: text/html\r\n");
	} else {
		dsbPrintf(out, "Content-Type: text/plain\r\n");
	}

	dsbPrintf(out, "Content-Transfer-Encoding: quoted-printable\r\n\r\n");
	qp = mimeQpEncodeString((u_char *)in->str, true);
	dsbnCat(out, qp->str, qp->len);
	dsbDestroy(qp);
	if (Mopts.attach) {
		attachFiles(border, out);
		dsbPrintf(out, "\r\n--%s--\r\n", border);
	}
	return 0;
}
Exemple #9
0
/** 
 * Makes a standard plain text message while taking into
 * account the MIME message types and boundary's needed
 * if and when a file is attached.
**/
static int
makeMessage(dstrbuf *in, dstrbuf *out, const char *border, CharSetType charset)
{
	dstrbuf *enc=NULL;
	if (Mopts.attach) {
		dsbPrintf(out, "--%s\r\n", border);
		if (charset == IS_UTF8 || charset == IS_PARTIAL_UTF8) {
			dsbPrintf(out, "Content-Type: text/plain; charset=utf-8\r\n");
			if (IS_PARTIAL_UTF8) {
				dsbPrintf(out, "Content-Transfer-Encoding: quoted-printable\r\n");
				enc = mimeQpEncodeString((u_char *)in->str, true);
			} else {
				dsbPrintf(out, "Content-Transfer-Encoding: base64\r\n");
				enc = mimeB64EncodeString((u_char *)in->str, in->len, true);
			}
			dsbPrintf(out, "Content-Disposition: inline\r\n\r\n");
		} else if (Mopts.html) {
			dsbPrintf(out, "Content-Type: text/html\r\n\r\n");
			enc = DSB_NEW;
			dsbCat(enc, in->str);
		} else {
			dsbPrintf(out, "Content-Type: text/plain\r\n\r\n");
			enc = DSB_NEW;
			dsbCat(enc, in->str);
		}
	} else {
		if (charset == IS_UTF8) {
			enc = mimeB64EncodeString((u_char *)in->str, in->len, true);
		} else if (charset == IS_PARTIAL_UTF8) {
			enc = mimeQpEncodeString((u_char *)in->str, true);
		} else {
			enc = DSB_NEW;
			dsbCat(enc, in->str);
		}
	}
	dsbPrintf(out, "%s\r\n", enc->str);
	if (Mopts.attach) {
		if (attachFiles(border, out) == ERROR) {
			return ERROR;
		}
		dsbPrintf(out, "\r\n\r\n--%s--\r\n", border);
	}
	dsbDestroy(enc);
	return 0;
}
Exemple #10
0
dstrbuf *
encodeUtf8String(const u_char *str, bool use_qp)
{
	const u_int max_blk_len = 45;
	u_int i=max_blk_len;
	dstrbuf *enc, *dsb = DSB_NEW;
	size_t len = strlen((char *)str);

	if (use_qp) {
		// TODO: We need to break this up so that we're not 
		// creating extra long strings.
		enc = mimeQpEncodeString(str, false);
		dsbPrintf(dsb, "=?utf-8?q?%s?=", enc->str);
		i = len; // Just reset for now.
	} else {
		enc = mimeB64EncodeString(str, 
			(len > max_blk_len ? max_blk_len : len), false);
		dsbPrintf(dsb, "=?utf-8?b?%s?=", enc->str);
	}
	dsbDestroy(enc);

	/* If we have anymore data to encode, we have to do it by adding a newline
	   plus a space because each section can only be 75 chars long. */ 
	while (i < len) {
		size_t newlen = strlen((char *)str + i);
		/* only allow max_blk_len sections */
		if (newlen > max_blk_len) {
			newlen = max_blk_len;
		}
		enc = mimeB64EncodeString(str + i, newlen, false);
		dsbPrintf(dsb, "\r\n =?utf-8?b?%s?=", enc->str);
		dsbDestroy(enc);
		i += newlen;
	}
	return dsb;
}
Exemple #11
0
/** Print Date Headers **/
static void
printDateHeaders(dstrbuf *msg)
{
	time_t set_time;
	struct tm *lt;
	char buf[MAXBUF] = { 0 };

	set_time = time(&set_time);

#ifdef USE_GMT
	lt = gmtime(&set_time);
#else
	lt = localtime(&set_time);
#endif

#ifdef USE_GNU_STRFTIME
	strftime(buf, MAXBUF, "%a, %d %b %Y %H:%M:%S %z", lt);
#else
	strftime(buf, MAXBUF, "%a, %d %b %Y %H:%M:%S %Z", lt);
#endif

	dsbPrintf(msg, "Date: %s\r\n", buf);
}
Exemple #12
0
/**
 * Makes a message type specifically for gpg encryption and 
 * signing.  Specific MIME message descriptions are needed
 * when signing/encrypting a file before it is actuall signed
 * or encrypted.  This function takes care of that.
**/
static int
makeGpgMessage(dstrbuf *in, dstrbuf *out, const char *border)
{
    char *ptr=NULL;
	dstrbuf *qp=NULL;

	assert(in != NULL);
	assert(out != NULL);
	assert(border != NULL);

	if (Mopts.attach) {
		dsbPrintf(out, "Content-Type: multipart/mixed; "
			"boundary=\"%s\"\r\n\r\n", border);
		dsbPrintf(out, "\r\n--%s\r\n", border);
	}

	if (Mopts.html) {
		dsbPrintf(out, "Content-Type: text/html\r\n");
	} else {
		dsbPrintf(out, "Content-Type: text/plain\r\n");
	}

	dsbPrintf(out, "Content-Transfer-Encoding: quoted-printable\r\n\r\n");
	qp = mimeQpEncodeString((u_char *)in->str, true);
    /* Fix single dot on it's on line so we don't terminate the message prematurely. */
    dstrbuf *formatted = DSB_NEW;
    char previous='\0';
    for (ptr = qp->str; ptr && *ptr != '\0'; previous=*ptr, ptr++) {
        dsbCatChar(formatted, *ptr);
        /* If we have a dot starting on a newline. */
        if ((previous == '\n' || previous == '\r') && *ptr == '.') {
            dsbCatChar(formatted, '.');
        }
    }

	dsbDestroy(qp);
	dsbnCat(out, formatted->str, formatted->len);
    dsbDestroy(formatted);

	if (Mopts.attach) {
		attachFiles(border, out);
		dsbPrintf(out, "\r\n--%s--\r\n", border);
	}
	return 0;
}
Exemple #13
0
/**
 * Creates a signed message with gpg and takes into 
 * account the correct MIME message types to add to 
 * the message.
**/
static dstrbuf *
createGpgEmail(dstrbuf *msg, GpgCallType gpg_type)
{
	dstrbuf *tmpbuf=DSB_NEW;
	dstrbuf *gpgdata=NULL, *buf=DSB_NEW;
	dstrbuf *border1=NULL, *border2=NULL;

	assert(msg != NULL);

	/* Create two borders if we're attaching files */
	border1 = mimeMakeBoundary();
	if (Mopts.attach) {
		border2 = mimeMakeBoundary();
	} else {
		border2 = DSB_NEW;
	}

	if (makeGpgMessage(msg, tmpbuf, border2->str) < 0) {
		dsbDestroy(buf);
		buf=NULL;
		goto end;
	}

	gpgdata = callGpg(tmpbuf, gpg_type);
	if (!gpgdata) {
		dsbDestroy(buf);
		buf=NULL;
		goto end;
	}
	printHeaders(border1->str, buf, IS_ASCII);

	dsbPrintf(buf, "\r\n--%s\r\n", border1->str);
	if (gpg_type & GPG_ENC) {
		dsbPrintf(buf, "Content-Type: application/pgp-encrypted\r\n\r\n");
		dsbPrintf(buf, "Version: 1\r\n");
		dsbPrintf(buf, "\r\n--%s\r\n", border1->str);
		dsbPrintf(buf, "Content-type: application/octet-stream; "
			       "name=encrypted.asc\r\n\r\n");
	} else if (gpg_type & GPG_SIG) {
		dsbPrintf(buf, "%s\r\n", tmpbuf->str);
		dsbPrintf(buf, "\r\n--%s\r\n", border1->str);
		dsbPrintf(buf, "Content-Type: application/pgp-signature\r\n");
		dsbPrintf(buf, "Content-Description: This is a digitally signed message\r\n\r\n");
	} 
	dsbPrintf(buf, "%s", gpgdata->str);
	dsbPrintf(buf, "\r\n--%s--\r\n", border1->str);

end:
	dsbDestroy(tmpbuf);
	dsbDestroy(gpgdata);
	dsbDestroy(border1);
	dsbDestroy(border2);
	return buf;
}
Exemple #14
0
/** 
 * Makes a standard plain text message while taking into
 * account the MIME message types and boundary's needed
 * if and when a file is attached.
**/
static int
makeMessage(dstrbuf *in, dstrbuf *out, const char *border, CharSetType charset)
{
    char *ptr=NULL;
	dstrbuf *enc=NULL;

	if (Mopts.attach) {
		dsbPrintf(out, "--%s\r\n", border);
		if (charset == IS_UTF8 || charset == IS_PARTIAL_UTF8) {
			if (Mopts.html) {
				dsbPrintf(out, "Content-Type: text/html; charset=utf-8\r\n");
			} else {
				dsbPrintf(out, "Content-Type: text/plain; charset=utf-8\r\n");
			}
			if (IS_PARTIAL_UTF8) {
				dsbPrintf(out, "Content-Transfer-Encoding: quoted-printable\r\n");
				enc = mimeQpEncodeString((u_char *)in->str, true);
			} else {
				dsbPrintf(out, "Content-Transfer-Encoding: base64\r\n");
				enc = mimeB64EncodeString((u_char *)in->str, in->len, true);
			}
			dsbPrintf(out, "Content-Disposition: inline\r\n\r\n");
		} else if (Mopts.html) {
			dsbPrintf(out, "Content-Type: text/html\r\n\r\n");
			enc = DSB_NEW;
			dsbCat(enc, in->str);
		} else {
			dsbPrintf(out, "Content-Type: text/plain\r\n\r\n");
			enc = DSB_NEW;
			dsbCat(enc, in->str);
		}
	} else {
		if (charset == IS_UTF8) {
			enc = mimeB64EncodeString((u_char *)in->str, in->len, true);
		} else if (charset == IS_PARTIAL_UTF8) {
			enc = mimeQpEncodeString((u_char *)in->str, true);
		} else {
			enc = DSB_NEW;
			dsbCat(enc, in->str);
		}
	}

    /* Fix single dot on it's on line so we don't terminate the message prematurely. */
    dstrbuf *formatted = DSB_NEW;
    char previous='\0';
    for (ptr = enc->str; ptr && *ptr != '\0'; previous=*ptr, ptr++) {
        dsbCatChar(formatted, *ptr);
        /* If we have a dot starting on a newline. */
        if ((previous == '\n' || previous == '\r') && *ptr == '.') {
            dsbCatChar(formatted, '.');
        }
    }

    dsbDestroy(enc);
	dsbPrintf(out, "%s\r\n", formatted->str);

	if (Mopts.attach) {
		if (attachFiles(border, out) == ERROR) {
			return ERROR;
		}
		dsbPrintf(out, "\r\n\r\n--%s--\r\n", border);
	}
	dsbDestroy(formatted);
	return 0;
}
Exemple #15
0
static int
smtpAuthPlain(dsocket *sd, const char *user, const char *pass)
{
	int retval = 0;
	dstrbuf *data=NULL;
	dstrbuf *up = DSB_NEW;
	dstrbuf *rbuf = DSB_NEW;

	if (writeResponse(sd, "AUTH PLAIN\r\n") < 0) {
		smtpSetErr("Socket write error: smtp_auth_plain");
		retval = ERROR;
		goto end;
	}

#ifdef DEBUG_SMTP
	printf("--> AUTH PLAIN\n");
	fflush(stdout);
#endif

	retval = readResponse(sd, rbuf);
	if (retval != 334) {
		if (retval != ERROR) {
			smtpSetErr(rbuf->str);
		}
		retval = ERROR;
		goto end;
	}

#ifdef DEBUG_SMTP
	printf("<-- %s\n", rbuf->str);
	fflush(stdout);
#endif

	dsbPrintf(up, "%c%s%c%s", '\0', user, '\0', pass);
	data = mimeB64EncodeString((u_char *)up->str, up->len, false);
	if (writeResponse(sd, "%s\r\n", data->str) < 0) {
		smtpSetErr("Socket write error: smtp_auth_plain");
		retval = ERROR;
		goto end;
	}

#ifdef DEBUG_SMTP
	printf("--> %s\n", data->str);
	fflush(stdout);
#endif

	dsbClear(rbuf);
	retval = readResponse(sd, rbuf);
	if (retval != 235) {
		if (retval != ERROR) {
			smtpSetErr(rbuf->str);
		}
		retval = ERROR;
		goto end;
	}

#ifdef DEBUG_SMTP
	printf("<-- %s\n", rbuf->str);
	fflush(stdout);
#endif

end:
	dsbDestroy(up);
	dsbDestroy(data);
	dsbDestroy(rbuf);
	return retval;
}