/* * Claws Mail templates subsystem * Copyright (C) 2001 Alexander Barinov * Copyright (C) 2001-2021 The Claws Mail team * * 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 * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program 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 this program. If not, see . * */ #include "config.h" #include "defs.h" #include #include #include #include #include #include "utils.h" #include "template.h" #include "codeconv.h" #include "file-utils.h" static GSList *template_list; static Template *template_load(gchar *filename) { Template *tmpl; FILE *fp; gchar buf[BUFFSIZE]; gint bytes_read; if ((fp = claws_fopen(filename, "rb")) == NULL) { FILE_OP_ERROR(filename, "claws_fopen"); return NULL; } tmpl = g_new(Template, 1); tmpl->load_filename = g_strdup(filename); tmpl->name = NULL; tmpl->subject = NULL; tmpl->from = NULL; tmpl->to = NULL; tmpl->cc = NULL; tmpl->bcc = NULL; tmpl->replyto = NULL; tmpl->value = NULL; while (claws_fgets(buf, sizeof(buf), fp) != NULL) { if (buf[0] == '\n') break; else if (!g_ascii_strncasecmp(buf, "Name:", 5)) tmpl->name = g_strdup(g_strstrip(buf + 5)); else if (!g_ascii_strncasecmp(buf, "From:", 5)) tmpl->from = g_strdup(g_strstrip(buf + 5)); else if (!g_ascii_strncasecmp(buf, "To:", 3)) tmpl->to = g_strdup(g_strstrip(buf + 3)); else if (!g_ascii_strncasecmp(buf, "Cc:", 3)) tmpl->cc = g_strdup(g_strstrip(buf + 3)); else if (!g_ascii_strncasecmp(buf, "Bcc:", 4)) tmpl->bcc = g_strdup(g_strstrip(buf + 4)); else if (!g_ascii_strncasecmp(buf, "Reply-To:", 9)) tmpl->replyto = g_strdup(g_strstrip(buf + 9)); else if (!g_ascii_strncasecmp(buf, "Subject:", 8)) tmpl->subject = g_strdup(g_strstrip(buf + 8)); } if (!tmpl->name) { g_warning("wrong template format"); template_free(tmpl); claws_fclose(fp); return NULL; } if ((bytes_read = claws_fread(buf, 1, sizeof(buf), fp)) == 0) { if (claws_ferror(fp)) { FILE_OP_ERROR(filename, "claws_fread"); template_free(tmpl); claws_fclose(fp); return NULL; } } claws_fclose(fp); tmpl->value = g_strndup(buf, bytes_read); return tmpl; } void template_free(Template *tmpl) { g_free(tmpl->load_filename); g_free(tmpl->name); g_free(tmpl->subject); g_free(tmpl->from); g_free(tmpl->to); g_free(tmpl->cc); g_free(tmpl->bcc); g_free(tmpl->replyto); g_free(tmpl->value); g_free(tmpl); } static void template_clear_config(GSList *tmpl_list) { GSList *cur; Template *tmpl; for (cur = tmpl_list; cur != NULL; cur = cur->next) { tmpl = (Template *)cur->data; template_free(tmpl); } g_slist_free(tmpl_list); } static gint tmpl_compare(gconstpointer tmpl1, gconstpointer tmpl2) { gchar *basename1, *basename2; long filenum1, filenum2; gint ret = 0; if ((Template *)tmpl1 == NULL || (Template *)tmpl2 == NULL) return 0; if (((Template *)tmpl1)->load_filename == NULL || ((Template *)tmpl2)->load_filename == NULL) return 0; basename1 = g_path_get_basename(((Template *)tmpl1)->load_filename); basename2 = g_path_get_basename(((Template *)tmpl2)->load_filename); filenum1 = atol(basename1); filenum2 = atol(basename2); g_free(basename1); g_free(basename2); if (filenum1 == 0 || filenum2 == 0) return 0; if (filenum1 < filenum2) ret = -1; else if (filenum1 > filenum2) ret = 1; return ret; } GSList *template_read_config(void) { const gchar *path; GDir *dir; const gchar *dir_name; GSList *tmpl_list = NULL; path = get_template_dir(); debug_print("%s:%d reading templates dir %s\n", __FILE__, __LINE__, path); if (!is_dir_exist(path)) { if (make_dir(path) < 0) return NULL; } if ((dir = g_dir_open(path, 0, NULL)) == NULL) { g_warning("failed to open directory: '%s'", path); return NULL; } while ((dir_name = g_dir_read_name(dir)) != NULL) { Template *tmpl; GStatBuf s; gchar *filename = g_strconcat(path, G_DIR_SEPARATOR_S, dir_name, NULL); if (g_stat(filename, &s) != 0 || !S_ISREG(s.st_mode) ) { debug_print("%s:%d %s is not an ordinary file\n", __FILE__, __LINE__, filename); g_free(filename); continue; } tmpl = template_load(filename); if (tmpl) tmpl_list = g_slist_insert_sorted(tmpl_list, tmpl, tmpl_compare); g_free(filename); } g_dir_close(dir); return tmpl_list; } #define TRY(func) { \ if (!(func)) \ { \ g_warning("failed to write template to file"); \ if (fp) claws_fclose(fp); \ if (new) claws_unlink(new); \ g_free(new); \ g_free(filename); \ return; \ } \ } #define TRY_NO_CLOSE(func) { \ if (!(func)) \ { \ g_warning("failed to write template to file"); \ if (new) claws_unlink(new); \ g_free(new); \ g_free(filename); \ return; \ } \ } static void template_write_config(GSList *tmpl_list) { const gchar *path; GSList *cur; Template *tmpl; FILE *fp; gint tmpl_num; debug_print("%s:%d writing templates\n", __FILE__, __LINE__); path = get_template_dir(); if (!is_dir_exist(path)) { if (is_file_exist(path)) { g_warning("file '%s' already exists", path); return; } if (make_dir(path) < 0) return; } for (cur = tmpl_list, tmpl_num = 1; cur != NULL; cur = cur->next, tmpl_num++) { gchar *filename, *new = NULL; tmpl = cur->data; filename = g_strconcat(path, G_DIR_SEPARATOR_S, itos(tmpl_num), NULL); if (is_file_exist(filename)) { new = g_strconcat(filename, ".new", NULL); } if ((fp = claws_fopen(new?new:filename, "wb")) == NULL) { FILE_OP_ERROR(new?new:filename, "claws_fopen"); g_free(new); g_free(filename); return; } TRY(fprintf(fp, "Name: %s\n", tmpl->name) > 0); if (tmpl->subject && *tmpl->subject != '\0') TRY(fprintf(fp, "Subject: %s\n", tmpl->subject) > 0); if (tmpl->from && *tmpl->from != '\0') TRY(fprintf(fp, "From: %s\n", tmpl->from) > 0); if (tmpl->to && *tmpl->to != '\0') TRY(fprintf(fp, "To: %s\n", tmpl->to) > 0); if (tmpl->cc && *tmpl->cc != '\0') TRY(fprintf(fp, "Cc: %s\n", tmpl->cc) > 0); if (tmpl->bcc && *tmpl->bcc != '\0') TRY(fprintf(fp, "Bcc: %s\n", tmpl->bcc) > 0); if (tmpl->replyto && *tmpl->replyto != '\0') TRY(fprintf(fp, "Reply-To: %s\n", tmpl->replyto) > 0); TRY(claws_fputs("\n", fp) != EOF); if (tmpl->value && *tmpl->value != '\0') { TRY(claws_fwrite(tmpl->value, sizeof(gchar), strlen(tmpl->value), fp) == strlen(tmpl->value)); } else { TRY(claws_fwrite("", sizeof(gchar), 1, fp) == 1); } TRY_NO_CLOSE(claws_safe_fclose(fp) != EOF); if (new) { if (rename_force(new, filename) < 0) { FILE_OP_ERROR(new, "rename"); } } g_free(new); g_free(filename); } /* remove other templates */ while (TRUE) { gchar *filename = g_strconcat(path, G_DIR_SEPARATOR_S, itos(tmpl_num), NULL); if (is_file_exist(filename)) { debug_print("removing old template %d\n", tmpl_num); claws_unlink(filename); g_free(filename); } else { g_free(filename); break; } tmpl_num++; } } GSList *template_get_config(void) { if (!template_list) template_list = template_read_config(); return template_list; } void template_set_config(GSList *tmpl_list) { template_clear_config(template_list); template_write_config(tmpl_list); template_list = tmpl_list; }