/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2002 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include <sys/wait.h>
#include <dirent.h>
#include <time.h>
+#include <regex.h>
#include "intl.h"
#include "utils.h"
#include "socket.h"
+#include "../codeconv.h"
#define BUFFSIZE 8192
g_hash_table_foreach(table, hash_free_value_mem_func, NULL);
}
+gint str_case_equal(gconstpointer v, gconstpointer v2)
+{
+ return strcasecmp((const gchar *)v, (const gchar *)v2) == 0;
+}
+
+guint str_case_hash(gconstpointer key)
+{
+ const gchar *p = key;
+ guint h = *p;
+
+ if (h) {
+ h = tolower(h);
+ for (p += 1; *p != '\0'; p++)
+ h = (h << 5) - h + tolower(*p);
+ }
+
+ return h;
+}
+
void ptr_array_free_strings(GPtrArray *array)
{
gint i;
static gchar str[10];
if (size < 1024)
- g_snprintf(str, sizeof(str), "%dB", (gint)size);
+ g_snprintf(str, sizeof(str), _("%dB"), (gint)size);
else if (size >> 10 < 1024)
- g_snprintf(str, sizeof(str), "%.1fKB", (gfloat)size / (1 << 10));
+ g_snprintf(str, sizeof(str), _("%.1fKB"), (gfloat)size / (1 << 10));
else if (size >> 20 < 1024)
- g_snprintf(str, sizeof(str), "%.2fMB", (gfloat)size / (1 << 20));
+ g_snprintf(str, sizeof(str), _("%.2fMB"), (gfloat)size / (1 << 20));
else
- g_snprintf(str, sizeof(str), "%.2fGB", (gfloat)size / (1 << 30));
+ g_snprintf(str, sizeof(str), _("%.2fGB"), (gfloat)size / (1 << 30));
return str;
}
return NULL;
}
+gint get_mbs_len(const gchar *s)
+{
+ const gchar *p = s;
+ gint mb_len;
+ gint len = 0;
+
+ if (!p)
+ return -1;
+
+ while (*p != '\0') {
+ mb_len = mblen(p, MB_LEN_MAX);
+ if (mb_len == 0)
+ break;
+ else if (mb_len < 0)
+ return -1;
+ else
+ len++;
+
+ p += mb_len;
+ }
+
+ return len;
+}
+
/* Examine if next block is non-ASCII string */
gboolean is_next_nonascii(const guchar *s)
{
Xstrdup_a(str1, s1, return -1);
Xstrdup_a(str2, s2, return -1);
- trim_subject(str1);
- trim_subject(str2);
+ trim_subject_for_compare(str1);
+ trim_subject_for_compare(str2);
if (!*str1 || !*str2) return -1;
return strcmp(str1, str2);
}
-void trim_subject(gchar *str)
+gint subject_compare_for_sort(const gchar *s1, const gchar *s2)
+{
+ gchar *str1, *str2;
+
+ if (!s1 || !s2) return -1;
+
+ Xstrdup_a(str1, s1, return -1);
+ Xstrdup_a(str2, s2, return -1);
+
+ trim_subject_for_sort(str1);
+ trim_subject_for_sort(str2);
+
+ return strcasecmp(str1, str2);
+}
+
+void trim_subject_for_compare(gchar *str)
{
gchar *srcp;
eliminate_parenthesis(str, '(', ')');
g_strstrip(str);
- while (!strncasecmp(str, "Re:", 3)) {
- srcp = str + 3;
- while (isspace(*srcp)) srcp++;
+ srcp = str + subject_get_prefix_length(str);
+ if (srcp != str)
+ memmove(str, srcp, strlen(srcp) + 1);
+}
+
+void trim_subject_for_sort(gchar *str)
+{
+ gchar *srcp;
+
+ g_strstrip(str);
+
+ srcp = str + subject_get_prefix_length(str);
+ if (srcp != str)
memmove(str, srcp, strlen(srcp) + 1);
+}
+
+void trim_subject(gchar *str)
+{
+ register gchar *srcp, *destp;
+ gchar op, cl;
+ gint in_brace;
+
+ destp = str + subject_get_prefix_length(str);
+
+ if (*destp == '[') {
+ op = '[';
+ cl = ']';
+ } else if (*destp == '(') {
+ op = '(';
+ cl = ')';
+ } else
+ return;
+
+ srcp = destp + 1;
+ in_brace = 1;
+ while (*srcp) {
+ if (*srcp == op)
+ in_brace++;
+ else if (*srcp == cl)
+ in_brace--;
+ srcp++;
+ if (in_brace == 0)
+ break;
}
+ while (isspace(*srcp)) srcp++;
+ memmove(destp, srcp, strlen(srcp) + 1);
}
void eliminate_parenthesis(gchar *str, gchar op, gchar cl)
*destp = '\0';
}
-void extract_one_parenthesis_with_skip_quote(gchar *str, gchar quote_chr,
- gchar op, gchar cl)
-{
- register gchar *srcp, *destp;
- gint in_brace;
- gboolean in_quote = FALSE;
-
- srcp = destp = str;
-
- if ((srcp = strchr_with_skip_quote(destp, quote_chr, op))) {
- memmove(destp, srcp + 1, strlen(srcp));
- in_brace = 1;
- while(*destp) {
- if (*destp == op && !in_quote)
- in_brace++;
- else if (*destp == cl && !in_quote)
- in_brace--;
- else if (*destp == quote_chr)
- in_quote ^= TRUE;
-
- if (in_brace == 0)
- break;
-
- destp++;
- }
- }
- *destp = '\0';
-}
-
void extract_parenthesis_with_skip_quote(gchar *str, gchar quote_chr,
gchar op, gchar cl)
{
g_strstrip(str);
}
-GSList *address_list_append(GSList *addr_list, const gchar *str)
+void extract_list_id_str(gchar *str)
+{
+ if (strchr_with_skip_quote(str, '"', '<'))
+ extract_parenthesis_with_skip_quote(str, '"', '<', '>');
+ g_strstrip(str);
+}
+
+static GSList *address_list_append_real(GSList *addr_list, const gchar *str, gboolean removecomments)
{
gchar *work;
gchar *workp;
Xstrdup_a(work, str, return addr_list);
- eliminate_address_comment(work);
+ if (removecomments)
+ eliminate_address_comment(work);
workp = work;
while (workp && *workp) {
} else
next = NULL;
- if (strchr_with_skip_quote(workp, '"', '<'))
+ if (removecomments && strchr_with_skip_quote(workp, '"', '<'))
extract_parenthesis_with_skip_quote
(workp, '"', '<', '>');
return addr_list;
}
+GSList *address_list_append(GSList *addr_list, const gchar *str)
+{
+ return address_list_append_real(addr_list, str, TRUE);
+}
+
+GSList *address_list_append_with_comments(GSList *addr_list, const gchar *str)
+{
+ return address_list_append_real(addr_list, str, FALSE);
+}
+
GSList *references_list_append(GSList *msgid_list, const gchar *str)
{
const gchar *strp;
gboolean is_ascii_str(const guchar *str)
{
+ g_return_val_if_fail(str, FALSE);
+
while (*str != '\0') {
if (*str != '\t' && *str != ' ' &&
*str != '\r' && *str != '\n' &&
gchar *abbrev_group;
gchar *ap;
const gchar *p = group;
- gint count = 0;
+ const gchar *last;
+ g_return_val_if_fail(group != NULL, NULL);
+
+ last = group + strlen(group);
abbrev_group = ap = g_malloc(strlen(group) + 1);
while (*p) {
while (*p == '.')
*ap++ = *p++;
-
- if ((strlen( p) + count) > len && strchr(p, '.')) {
+ if ((ap - abbrev_group) + (last - p) > len && strchr(p, '.')) {
*ap++ = *p++;
while (*p != '.') p++;
} else {
- strcpy( ap, p);
+ strcpy(ap, p);
return abbrev_group;
}
- count = count + 2;
}
*ap = '\0';
{
GList *result = NULL;
const gchar *p, *q;
- gchar *file;
+ gchar *escaped_utf8uri;
p = uri_list;
if (*p != '#') {
while (isspace(*p)) p++;
if (!strncmp(p, "file:", 5)) {
- p += 5;
q = p;
+ q += 5;
while (*q && *q != '\n' && *q != '\r') q++;
if (q > p) {
+ gchar *file, *locale_file = NULL;
q--;
while (q > p && isspace(*q)) q--;
- file = g_malloc(q - p + 2);
- strncpy(file, p, q - p + 1);
- file[q - p + 1] = '\0';
- result = g_list_append(result,file);
+ Xalloca(escaped_utf8uri, q - p + 2,
+ return result);
+ Xalloca(file, q - p + 2,
+ return result);
+ *file = '\0';
+ strncpy(escaped_utf8uri, p, q - p + 1);
+ escaped_utf8uri[q - p + 1] = '\0';
+ decode_uri(file, escaped_utf8uri);
+#warning FIXME_GTK2 /* should we use g_filename_from_utf8()? */
+ /*
+ * g_filename_from_uri() rejects escaped/locale encoded uri
+ * string which come from Nautilus.
+ */
+ if (g_utf8_validate(file, -1, NULL))
+ locale_file
+ = conv_codeset_strdup(
+ file + 5,
+ CS_UTF_8,
+ conv_get_current_charset_str());
+ if (!locale_file)
+ locale_file = g_strdup(file + 5);
+ result = g_list_append(result, locale_file);
}
}
}
* but as long as we are not able to do our own extensions to glibc, we do
* it here.
*/
-gchar *get_home_dir(void)
+const gchar *get_home_dir(void)
{
#if HAVE_DOSISH_SYSTEM
static gchar *home_dir;
#endif
}
-gchar *get_rc_dir(void)
+const gchar *get_rc_dir(void)
{
static gchar *rc_dir = NULL;
return rc_dir;
}
-gchar *get_news_cache_dir(void)
+const gchar *get_news_cache_dir(void)
{
static gchar *news_cache_dir = NULL;
return news_cache_dir;
}
-gchar *get_imap_cache_dir(void)
+const gchar *get_imap_cache_dir(void)
{
static gchar *imap_cache_dir = NULL;
return imap_cache_dir;
}
-gchar *get_mbox_cache_dir(void)
+const gchar *get_mbox_cache_dir(void)
{
static gchar *mbox_cache_dir = NULL;
return mbox_cache_dir;
}
-gchar *get_mime_tmp_dir(void)
+const gchar *get_mime_tmp_dir(void)
{
static gchar *mime_tmp_dir = NULL;
return mime_tmp_dir;
}
-gchar *get_template_dir(void)
+const gchar *get_template_dir(void)
{
static gchar *template_dir = NULL;
return template_dir;
}
-gchar *get_header_cache_dir(void)
+const gchar *get_header_cache_dir(void)
{
static gchar *header_dir = NULL;
return header_dir;
}
-gchar *get_tmp_dir(void)
+const gchar *get_tmp_dir(void)
{
static gchar *tmp_dir = NULL;
return tmp_file;
}
-gchar *get_domain_name(void)
+const gchar *get_domain_name(void)
{
static gchar *domain_name = NULL;
/* convert line endings into CRLF. If the last line doesn't end with
* linebreak, add it.
*/
+gchar *canonicalize_str(const gchar *str)
+{
+ const gchar *p;
+ guint new_len = 0;
+ gchar *out, *outp;
+
+ for (p = str; *p != '\0'; ++p) {
+ if (*p != '\r') {
+ ++new_len;
+ if (*p == '\n')
+ ++new_len;
+ }
+ }
+ if (p == str || *(p - 1) != '\n')
+ new_len += 2;
+
+ out = outp = g_malloc(new_len + 1);
+ for (p = str; *p != '\0'; ++p) {
+ if (*p != '\r') {
+ if (*p == '\n')
+ *outp++ = '\r';
+ *outp++ = *p;
+ }
+ }
+ if (p == str || *(p - 1) != '\n') {
+ *outp++ = '\r';
+ *outp++ = '\n';
+ }
+ *outp = '\0';
+
+ return out;
+}
+
gint canonicalize_file(const gchar *src, const gchar *dest)
{
FILE *src_fp, *dest_fp;
}
if (ferror(src_fp)) {
- FILE_OP_ERROR(src, "fread");
+ FILE_OP_ERROR(src, "fgets");
err = TRUE;
}
fclose(src_fp);
return 0;
}
+gint uncanonicalize_file(const gchar *src, const gchar *dest)
+{
+ FILE *src_fp, *dest_fp;
+ gchar buf[BUFFSIZE];
+ gboolean err = FALSE;
+
+ if ((src_fp = fopen(src, "rb")) == NULL) {
+ FILE_OP_ERROR(src, "fopen");
+ return -1;
+ }
+
+ if ((dest_fp = fopen(dest, "wb")) == NULL) {
+ FILE_OP_ERROR(dest, "fopen");
+ fclose(src_fp);
+ return -1;
+ }
+
+ if (change_file_mode_rw(dest_fp, dest) < 0) {
+ FILE_OP_ERROR(dest, "chmod");
+ g_warning("can't change file mode\n");
+ }
+
+ while (fgets(buf, sizeof(buf), src_fp) != NULL) {
+ strcrchomp(buf);
+ if (fputs(buf, dest_fp) == EOF) {
+ g_warning("writing to %s failed.\n", dest);
+ fclose(dest_fp);
+ fclose(src_fp);
+ unlink(dest);
+ return -1;
+ }
+ }
+
+ if (ferror(src_fp)) {
+ FILE_OP_ERROR(src, "fgets");
+ err = TRUE;
+ }
+ fclose(src_fp);
+ if (fclose(dest_fp) == EOF) {
+ FILE_OP_ERROR(dest, "fclose");
+ err = TRUE;
+ }
+
+ if (err) {
+ unlink(dest);
+ return -1;
+ }
+
+ return 0;
+}
+
+gint uncanonicalize_file_replace(const gchar *file)
+{
+ gchar *tmp_file;
+
+ tmp_file = get_tmp_file();
+
+ if (uncanonicalize_file(file, tmp_file) < 0) {
+ g_free(tmp_file);
+ return -1;
+ }
+
+ if (move_file(tmp_file, file, TRUE) < 0) {
+ g_warning("can't replace %s .\n", file);
+ unlink(tmp_file);
+ g_free(tmp_file);
+ return -1;
+ }
+
+ g_free(tmp_file);
+ return 0;
+}
+
+gchar *normalize_newlines(const gchar *str)
+{
+ const gchar *p = str;
+ gchar *out, *outp;
+
+ out = outp = g_malloc(strlen(str) + 1);
+ for (p = str; *p != '\0'; ++p) {
+ if (*p == '\r') {
+ if (*(p + 1) != '\n')
+ *outp++ = '\n';
+ } else
+ *outp++ = *p;
+ }
+
+ *outp = '\0';
+
+ return out;
+}
+
+gchar *get_outgoing_rfc2822_str(FILE *fp)
+{
+ gchar buf[BUFFSIZE];
+ GString *str;
+ gchar *ret;
+
+ str = g_string_new(NULL);
+
+ /* output header part */
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ strretchomp(buf);
+ if (!g_strncasecmp(buf, "Bcc:", 4)) {
+ gint next;
+
+ for (;;) {
+ next = fgetc(fp);
+ if (next == EOF)
+ break;
+ else if (next != ' ' && next != '\t') {
+ ungetc(next, fp);
+ break;
+ }
+ if (fgets(buf, sizeof(buf), fp) == NULL)
+ break;
+ }
+ } else {
+ g_string_append(str, buf);
+ g_string_append(str, "\r\n");
+ if (buf[0] == '\0')
+ break;
+ }
+ }
+
+ /* output body part */
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ strretchomp(buf);
+ if (buf[0] == '.')
+ g_string_append_c(str, '.');
+ g_string_append(str, buf);
+ g_string_append(str, "\r\n");
+ }
+
+ ret = str->str;
+ g_string_free(str, FALSE);
+
+ return ret;
+}
+
gint change_file_mode_rw(FILE *fp, const gchar *file)
{
#if HAVE_FCHMOD
gchar *file_read_to_str(const gchar *file)
{
- GByteArray *array;
FILE *fp;
- gchar buf[BUFSIZ];
- gint n_read;
gchar *str;
g_return_val_if_fail(file != NULL, NULL);
return NULL;
}
+ str = file_read_stream_to_str(fp);
+
+ fclose(fp);
+
+ return str;
+}
+
+gchar *file_read_stream_to_str(FILE *fp)
+{
+ GByteArray *array;
+ gchar buf[BUFSIZ];
+ gint n_read;
+ gchar *str;
+
+ g_return_val_if_fail(fp != NULL, NULL);
+
array = g_byte_array_new();
while ((n_read = fread(buf, sizeof(gchar), sizeof(buf), fp)) > 0) {
}
if (ferror(fp)) {
- FILE_OP_ERROR(file, "fread");
- fclose(fp);
+ FILE_OP_ERROR("file stream", "fread");
g_byte_array_free(array, TRUE);
return NULL;
}
- fclose(fp);
-
buf[0] = '\0';
g_byte_array_append(array, buf, 1);
str = (gchar *)array->data;
return ret;
}
+gchar *get_command_output(const gchar *cmdline)
+{
+ gchar buf[BUFFSIZE];
+ FILE *fp;
+ GString *str;
+ gchar *ret;
+
+ g_return_val_if_fail(cmdline != NULL, NULL);
+
+ if ((fp = popen(cmdline, "r")) == NULL) {
+ FILE_OP_ERROR(cmdline, "popen");
+ return NULL;
+ }
+
+ str = g_string_new("");
+
+ while (fgets(buf, sizeof(buf), fp) != NULL)
+ g_string_append(str, buf);
+
+ pclose(fp);
+
+ ret = str->str;
+ g_string_free(str, FALSE);
+
+ return ret;
+}
+
static gint is_unchanged_uri_char(char c)
{
switch (c) {
} else if (!strncmp(zone, "UT" , 2) ||
!strncmp(zone, "GMT", 2)) {
remoteoffset = 0;
- } else if (strlen(zone3) == 3 &&
- (p = strstr(ustzstr, zone3)) != NULL &&
- (p - ustzstr) % 3 == 0) {
- iustz = ((gint)(p - ustzstr) / 3 + 1) / 2 - 8;
- remoteoffset = iustz * 3600;
+ } else if (strlen(zone3) == 3) {
+ for (p = ustzstr; *p != '\0'; p += 3) {
+ if (!strncasecmp(p, zone3, 3)) {
+ iustz = ((gint)(p - ustzstr) / 3 + 1) / 2 - 8;
+ remoteoffset = iustz * 3600;
+ break;
+ }
+ }
+ if (*p == '\0')
+ return -1;
} else if (strlen(zone3) == 1) {
switch (zone[0]) {
case 'Z': remoteoffset = 0; break;
default: remoteoffset = 0; break;
}
remoteoffset = remoteoffset * 3600;
- }
+ } else
+ return -1;
return remoteoffset;
}
off = 23 * 60 + 59; /* if not, insert silly value */
if (off <= -24 * 60)
off = -(23 * 60 + 59);
- if (off > 12 * 60)
- off -= 24 * 60;
- if (off < -12 * 60)
- off += 24 * 60;
return off * 60;
}
debug_mode = mode;
}
-gboolean debug_get_mode()
+gboolean debug_get_mode(void)
{
return debug_mode;
}
{
if (subject == NULL)
subject = "";
-
- if (g_strncasecmp(subject, "Re: ", 4) == 0)
- return g_hash_table_lookup(subject_table, subject + 4);
else
- return g_hash_table_lookup(subject_table, subject);
+ subject += subject_get_prefix_length(subject);
+
+ return g_hash_table_lookup(subject_table, subject);
}
void subject_table_insert(GHashTable *subject_table, gchar * subject,
void * data)
{
- if (subject == NULL)
- return;
- if (* subject == 0)
- return;
- if (g_strcasecmp(subject, "Re:") == 0)
+ if (subject == NULL || *subject == 0)
return;
- if (g_strcasecmp(subject, "Re: ") == 0)
- return;
-
- if (g_strncasecmp(subject, "Re: ", 4) == 0)
- g_hash_table_insert(subject_table, subject + 4, data);
- else
- g_hash_table_insert(subject_table, subject, data);
+ subject += subject_get_prefix_length(subject);
+ g_hash_table_insert(subject_table, subject, data);
}
void subject_table_remove(GHashTable *subject_table, gchar * subject)
if (subject == NULL)
return;
- if (g_strncasecmp(subject, "Re: ", 4) == 0)
- g_hash_table_remove(subject_table, subject + 4);
- else
- g_hash_table_remove(subject_table, subject);
+ subject += subject_get_prefix_length(subject);
+ g_hash_table_remove(subject_table, subject);
}
-gboolean subject_is_reply(const gchar *subject)
-{
- /* XXX: just simply here so someone can handle really
- * advanced Re: detection like "Re[4]", "ANTW:" or
- * Re: Re: Re: Re: Re: Re: Re: Re:" stuff. */
- if (subject == NULL) return FALSE;
- else return 0 == g_strncasecmp(subject, "Re: ", 4);
+/*!
+ *\brief Check if a string is prefixed with known (combinations)
+ * of prefixes. The function assumes that each prefix
+ * is terminated by zero or exactly _one_ space.
+ *
+ *\param str String to check for a prefixes
+ *
+ *\return int Number of chars in the prefix that should be skipped
+ * for a "clean" subject line. If no prefix was found, 0
+ * is returned.
+ */
+int subject_get_prefix_length(const gchar *subject)
+{
+ /*!< Array with allowable reply prefixes regexps. */
+ static const gchar * const prefixes[] = {
+ "Re\\:", /* "Re:" */
+ "Re\\[[1-9][0-9]*\\]\\:", /* "Re[XXX]:" (non-conforming news mail clients) */
+ "Antw\\:", /* "Antw:" (Dutch / German Outlook) */
+ "Aw\\:", /* "Aw:" (German) */
+ "Antwort\\:", /* "Antwort:" (German Lotus Notes) */
+ "Res\\:", /* "Res:" (Brazilian Outlook) */
+ "Fw\\:", /* "Fw:" Forward */
+ "Enc\\:" /* "Enc:" Forward (Brazilian Outlook) */
+ /* add more */
+ };
+ const int PREFIXES = sizeof prefixes / sizeof prefixes[0];
+ int n;
+ regmatch_t pos;
+ static regex_t regex;
+ static gboolean init_;
+
+ if (!subject) return 0;
+ if (!*subject) return 0;
+
+ if (!init_) {
+ GString *s = g_string_new("");
+
+ for (n = 0; n < PREFIXES; n++)
+ /* Terminate each prefix regexpression by a
+ * "\ ?" (zero or ONE space), and OR them */
+ g_string_sprintfa(s, "(%s\\ ?)%s",
+ prefixes[n],
+ n < PREFIXES - 1 ?
+ "|" : "");
+
+ g_string_prepend(s, "(");
+ g_string_append(s, ")+"); /* match at least once */
+ g_string_prepend(s, "^\\ *"); /* from beginning of line */
+
+
+ /* We now have something like "^\ *((PREFIX1\ ?)|(PREFIX2\ ?))+"
+ * TODO: Should this be "^\ *(((PREFIX1)|(PREFIX2))\ ?)+" ??? */
+ if (regcomp(®ex, s->str, REG_EXTENDED | REG_ICASE)) {
+ debug_print("Error compiling regexp %s\n", s->str);
+ g_string_free(s, TRUE);
+ return 0;
+ } else {
+ init_ = TRUE;
+ g_string_free(s, TRUE);
+ }
+ }
+
+ if (!regexec(®ex, subject, 1, &pos, 0) && pos.rm_so != -1)
+ return pos.rm_eo;
+ else
+ return 0;
}
FILE *get_tmpfile_in_dir(const gchar *dir, gchar **filename)
/* allow Mutt-like patterns in quick search */
gchar *expand_search_string(const gchar *search_string)
{
- int i, len, new_len = 0;
+ int i = 0;
gchar term_char, save_char;
gchar *cmd_start, *cmd_end;
- gchar *new_str = NULL;
+ GString *matcherstr;
+ gchar *returnstr = NULL;
gchar *copy_str;
gboolean casesens, dontmatch;
/* list of allowed pattern abbreviations */
{ "h", "headers_part", 1, TRUE, TRUE },
{ "i", "header \"Message-Id\"", 1, TRUE, TRUE },
{ "I", "inreplyto", 1, TRUE, TRUE },
+ { "L", "locked", 0, FALSE, FALSE },
{ "n", "newsgroups", 1, TRUE, TRUE },
{ "N", "new", 0, FALSE, FALSE },
{ "O", "~new", 0, FALSE, FALSE },
if (cmds[i].command)
return copy_str;
+ matcherstr = g_string_sized_new(16);
cmd_start = cmd_end = copy_str;
while (cmd_end && *cmd_end) {
/* skip all white spaces */
if (!strcmp(cmd_start, cmds[i].abbreviated)) {
/* restore character */
*cmd_end = save_char;
- len = strlen(cmds[i].command) + 1;
- if (dontmatch)
- len++;
- if (casesens)
- len++;
/* copy command */
- if (new_str) {
- new_len += 1;
- new_str = g_realloc(new_str, new_len);
- strcat(new_str, " ");
+ if (matcherstr->len > 0) {
+ g_string_append(matcherstr, " ");
}
- new_len += (len + 1);
- new_str = g_realloc(new_str, new_len);
- if (new_len == len + 1)
- *new_str = '\0';
if (dontmatch)
- strcat(new_str, "~");
- strcat(new_str, cmds[i].command);
- strcat(new_str, " ");
+ g_string_append(matcherstr, "~");
+ g_string_append(matcherstr, cmds[i].command);
+ g_string_append(matcherstr, " ");
/* stop if no params required */
if (cmds[i].numparams == 0)
save_char = *cmd_end;
*cmd_end = '\0';
- new_len += strlen(cmd_start);
-
- /* do we need to add regexpcase ? */
- if (cmds[i].qualifier)
- new_len += 10; /* "regexpcase " */
-
- if (term_char != '"')
- new_len += 2;
- new_str = g_realloc(new_str, new_len);
-
if (cmds[i].qualifier) {
if (casesens)
- strcat(new_str, "regexp ");
+ g_string_append(matcherstr, "regexp ");
else
- strcat(new_str, "regexpcase ");
+ g_string_append(matcherstr, "regexpcase ");
}
/* do we need to add quotes ? */
if (cmds[i].quotes && term_char != '"')
- strcat(new_str, "\"");
+ g_string_append(matcherstr, "\"");
/* copy actual parameter */
- strcat(new_str, cmd_start);
+ g_string_append(matcherstr, cmd_start);
/* do we need to add quotes ? */
if (cmds[i].quotes && term_char != '"')
- strcat(new_str, "\"");
+ g_string_append(matcherstr, "\"");
/* restore original character */
*cmd_end = save_char;
}
g_free(copy_str);
- return new_str;
+ returnstr = matcherstr->str;
+ g_string_free(matcherstr, FALSE);
+ return returnstr;
+}
+
+guint g_stricase_hash(gconstpointer gptr)
+{
+ guint hash_result = 0;
+ const char *str;
+
+ for (str = gptr; str && *str; str++) {
+ if (isupper(*str)) hash_result += (*str + ' ');
+ else hash_result += *str;
+ }
+
+ return hash_result;
+}
+
+gint g_stricase_equal(gconstpointer gptr1, gconstpointer gptr2)
+{
+ const char *str1 = gptr1;
+ const char *str2 = gptr2;
+
+ return !strcasecmp(str1, str2);
}
+gint g_int_compare(gconstpointer a, gconstpointer b)
+{
+ return GPOINTER_TO_INT(a) - GPOINTER_TO_INT(b);
+}
+
+gchar *generate_msgid(const gchar *address, gchar *buf, gint len)
+{
+ /* steal from compose.c::compose_generate_msgid() */
+ struct tm *lt;
+ time_t t;
+ gchar *addr;
+
+ t = time(NULL);
+ lt = localtime(&t);
+
+ if (address && *address) {
+ if (strchr(address, '@'))
+ addr = g_strdup(address);
+ else
+ addr = g_strconcat(address, "@", get_domain_name(), NULL);
+ } else
+ addr = g_strconcat(g_get_user_name(), "@", get_domain_name(),
+ NULL);
+
+ g_snprintf(buf, len, "%04d%02d%02d%02d%02d%02d.%08x.%s",
+ lt->tm_year + 1900, lt->tm_mon + 1,
+ lt->tm_mday, lt->tm_hour,
+ lt->tm_min, lt->tm_sec,
+ (guint)random(), addr);
+
+ g_free(addr);
+ return buf;
+}
+
+/**
+ * Create a new boundary in a way that it is very unlikely that this
+ * will occur in the following text. It would be easy to ensure
+ * uniqueness if everything is either quoted-printable or base64
+ * encoded (note that conversion is allowed), but because MIME bodies
+ * may be nested, it may happen that the same boundary has already
+ * been used. We avoid scanning the message for conflicts and hope the
+ * best.
+ *
+ * boundary := 0*69<bchars> bcharsnospace
+ * bchars := bcharsnospace / " "
+ * bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
+ * "+" / "_" / "," / "-" / "." /
+ * "/" / ":" / "=" / "?"
+ *
+ * ":" and "," removed because of buggy MTAs
+ */
+
+gchar *generate_mime_boundary(void)
+{
+ static gchar tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "1234567890'()+_./=?";
+ gchar bufuniq[17];
+ gchar bufdate[BUFFSIZE];
+ int i, equal;
+ int pid;
+
+ pid = getpid();
+
+ /* We make the boundary depend on the pid, so that all running
+ * processed generate different values even when they have been
+ * started within the same second and srand48(time(NULL)) has been
+ * used. I can't see whether this is really an advantage but it
+ * doesn't do any harm.
+ */
+ equal = -1;
+ for (i = 0; i < sizeof(bufuniq) - 1; i++) {
+ bufuniq[i] = tbl[(lrand48() ^ pid) % (sizeof(tbl) - 1)]; /* fill with random */
+ if (bufuniq[i] == '=' && equal == -1)
+ equal = i;
+ }
+ bufuniq[i] = 0;
+
+ /* now make sure that we do have the sequence "=." in it which cannot
+ * be matched by quoted-printable or base64 encoding */
+ if (equal != -1 && (equal + 1) < i)
+ bufuniq[equal + 1] = '.';
+ else {
+ bufuniq[0] = '=';
+ bufuniq[1] = '.';
+ }
+
+ get_rfc822_date(bufdate, sizeof(bufdate));
+ subst_char(bufdate, ' ', '_');
+ subst_char(bufdate, ',', '_');
+ subst_char(bufdate, ':', '_');
+
+ return g_strdup_printf("Multipart_%s_%s",
+ bufdate, bufuniq);
+}