utils.c
上传用户:knt0001
上传日期:2022-01-28
资源大小:264k
文件大小:8k
- /**
- eMail is a command line SMTP client.
- Copyright (C) 2001 - 2008 email by Dean Jones
- Software supplied and written by http://www.cleancode.org
- This file is part of eMail.
- eMail is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- eMail is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with eMail; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- **/
- #if HAVE_CONFIG_H
- # include "config.h"
- #endif
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <ctype.h>
- #include <errno.h>
- #include <pwd.h>
- #include <sys/stat.h>
- #include <sys/wait.h>
- #include <sys/utsname.h>
- /* Autoconf manual suggests this. */
- #if TIME_WITH_SYS_TIME
- # include <sys/time.h>
- # include <time.h>
- #else
- # if HAVE_SYS_TIME_H
- # include <sys/time.h>
- # else
- # include <time.h>
- # endif
- #endif
- #include "email.h"
- #include "utils.h"
- #include "error.h"
- #include "mimeutils.h"
- /**
- * Return number of printable chars in a utf8 string
- */
- size_t
- utf8Strlen(const u_char *str)
- {
- size_t len=0;
- while (*str != ' ') {
- u_char fbyte = str[0];
- /* If greater than 0x7F (127) then it's not normal ASCII */
- if (fbyte > 0x7F) {
- /* It's a 2-byte sequence if it's between 0xC0(192)
- and 0xDF(223),
- It's a 3-byte sequence if it's between 0xE0(224)
- and 0xEF(239)
- It's a 4-byte sequence if it's between 0xF0(240)
- and 0xF4(244) */
- if (fbyte >= 0xC0 && fbyte <= 0xDF) {
- str += 2;
- } else if (fbyte >= 0xE0 && fbyte <= 0xEF) {
- str += 3;
- } else if (fbyte >= 0xF0 && fbyte <= 0xF4) {
- str += 4;
- } else {
- str += 1;
- }
- len++;
- } else {
- len++;
- }
- }
- return len;
- }
- /**
- * We're going to try and get the type of character set this
- * string is. We primarily just support UTF-8 and ASCII right
- * now. May support other charsets later.
- */
- CharSetType
- getCharSet(const u_char *str)
- {
- CharSetType type=IS_ASCII;
- u_int utf8=0, ascii=0;
- u_int percent_ascii=0;
- while (*str != ' ') {
- u_char fbyte = str[0];
- /* If greater than 0x7F (127) then it's not normal ASCII */
- if (fbyte > 0x7F) {
- /* It's a 2-byte sequence if it's between 0xC0(192)
- and 0xDF(223),
- It's a 3-byte sequence if it's between 0xE0(224)
- and 0xEF(239)
- It's a 4-byte sequence if it's between 0xF0(240)
- and 0xF4(244) */
- if (fbyte >= 0xC0 && fbyte <= 0xDF) {
- str += 2;
- } else if (fbyte >= 0xE0 && fbyte <= 0xEF) {
- str += 3;
- } else if (fbyte >= 0xF0 && fbyte <= 0xF4) {
- str += 4;
- } else {
- str += 1;
- }
- utf8++;
- } else {
- ascii++;
- str += 1;
- }
- }
- if (utf8) {
- /* If the string is 75% or more of ascii characters,
- we'll call it partial utf-8 */
- if (ascii > 0) {
- percent_ascii = ((float)ascii / (float)(ascii + utf8)) * 100;
- }
- if (percent_ascii >= 75) {
- type = IS_PARTIAL_UTF8;
- } else {
- type = IS_UTF8;
- }
- } else if (!utf8 && !ascii) {
- type = IS_OTHER;
- }
- return type;
- }
- 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, "rn =?utf-8?b?%s?=", enc->str);
- dsbDestroy(enc);
- i += newlen;
- }
- return dsb;
- }
- /**
- * takes a string that is a supposed file path, and
- * checks for certian wildcards ( like ~ for home directory )
- * and resolves to an actual absolute path.
- **/
- dstrbuf *
- expandPath(const char *path)
- {
- struct passwd *pw = NULL;
- dstrbuf *tmp = DSB_NEW;
- dstrbuf *ret = DSB_NEW;
- dsbCopy(tmp, path);
- if (tmp->len > 0 && tmp->str[0] == '&') {
- dsbCopy(ret, EMAIL_DIR);
- } else if (tmp->len > 0 && tmp->str[0] == '~') {
- if (tmp->str[1] == '/') {
- pw = getpwuid(getuid());
- } else {
- int pos = strfind(tmp->str, '/');
- if (pos >= 0) {
- char *p = substr(tmp->str, 1, pos-1);
- if (p) {
- pw = getpwnam(p);
- xfree(p);
- }
- }
- if (!pw) {
- pw = getpwuid(getuid());
- }
- }
- if (pw) {
- dsbCopy(ret, pw->pw_dir);
- }
- }
-
- if (ret->len > 0) {
- int pos = strfind(tmp->str, '/');
- if (pos > 0) {
- char *p = substr(tmp->str, pos, tmp->len);
- if (p) {
- dsbCat(ret, p);
- xfree(p);
- }
- }
- } else {
- dsbCopy(ret, path);
- }
- dsbDestroy(tmp);
- return ret;
- }
- int
- copyfile(const char *from, const char *to)
- {
- FILE *ffrom, *fto;
- dstrbuf *buf=NULL;
- ffrom = fopen(from, "r");
- fto = fopen(to, "w");
- if (!ffrom || !fto) {
- return -1;
- }
- buf = DSB_NEW;
- while (dsbFread(buf, MAXBUF, ffrom) > 0) {
- fwrite(buf->str, sizeof(char), buf->len, fto);
- dsbClear(buf);
- }
- dsbDestroy(buf);
- fclose(ffrom);
- fclose(fto);
- if (ferror(ffrom) || ferror(fto)) {
- return -1;
- }
- return 0;
- }
- /**
- * checks to see if the TEMP_FILE is around... if it is
- * it will move it to the users home directory as dead.letter.
- **/
- static void
- deadLetter()
- {
- dstrbuf *path = expandPath("~/dead.letter");
- FILE *out = fopen(path->str, "w");
- if (!out || !global_msg) {
- warning("Could not save dead letter to %s", path->str);
- } else {
- fwrite(global_msg->str, sizeof(char), global_msg->len, out);
- }
- dsbDestroy(path);
- }
- /**
- * Gererate a string of random characters
- **/
- static const char letters[] = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
- "0123456789";
- #define SIZEOF_LETTERS 62
- dstrbuf *
- randomString(size_t size)
- {
- size_t i;
- long randval;
- struct timeval mill;
- dstrbuf *ret = DSB_NEW;
- gettimeofday(&mill, NULL);
- srand((getuid() + getpid()) + (mill.tv_usec << 16));
- for (i=0; i < size; i++) {
- randval = rand() / (RAND_MAX / SIZEOF_LETTERS);
- dsbCatChar(ret, letters[randval]);
- }
- return ret;
- }
- /**
- * Get the first element from the Mopts.to list of emails
- * and return it without the name or formating. just the
- * email address itself.
- **/
- dstrbuf *
- getFirstEmail(void)
- {
- char *tmp=NULL;
- dstrbuf *buf = DSB_NEW;
- struct addr *a = (struct addr *)dlGetTop(Mopts.to);
- assert(a != NULL);
-
- /* If we haven't found a <, consider the e-mail unformatted. */
- tmp = strchr(a->email, '<');
- if (!tmp) {
- tmp = a->email;
- } else {
- /* strchr only brings us to the '<', Get past it */
- ++tmp;
- }
- dsbCopy(buf, tmp);
- tmp = strchr(buf->str, '>');
- if (tmp) {
- *tmp = ' ';
- }
- return buf;
- }
- /**
- * Exit just handles all the signals and exiting of the
- * program by freeing the allocated memory and writing
- * the dead.letter if we had a sudden interrupt...
- **/
- void
- properExit(int sig)
- {
- if (sig != 0 && global_msg) {
- deadLetter();
- }
- dsbDestroy(global_msg);
- /* Free lists */
- if (Mopts.attach) {
- dlDestroy(Mopts.attach);
- }
- if (Mopts.headers) {
- dlDestroy(Mopts.headers);
- }
- if (Mopts.to) {
- dlDestroy(Mopts.to);
- }
- if (Mopts.cc) {
- dlDestroy(Mopts.cc);
- }
- if (Mopts.bcc) {
- dlDestroy(Mopts.bcc);
- }
- dhDestroy(table);
- exit(sig);
- }
- int
- copyUpTo(dstrbuf *buf, int stop, FILE *in)
- {
- int ch;
- while ((ch = fgetc(in)) != EOF) {
- if (ch == '\') {
- ch = fgetc(in);
- if (ch == 'r') {
- ch = fgetc(in);
- }
- if (ch == 'n') {
- continue;
- }
- }
- if (ch == 'r') {
- ch = fgetc(in);
- if (ch == 'n') {
- return ch;
- }
- }
- if (ch == stop) {
- return ch;
- }
- dsbCatChar(buf, ch);
- }
- return ch;
- }