/* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client * Copyright (C) 1999-2012 Hiroyuki Yamamoto and 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 . * */ #ifdef HAVE_CONFIG_H # include "config.h" #include "claws-features.h" #endif #include #include "defs.h" #include #include "prefs.h" #include "utils.h" #include "file-utils.h" static gboolean prefs_is_readonly (const gchar *path); /*! *\brief Open preferences file for reading * *\param path Filename with path of preferences file to read * *\return PrefFile * preferences file struct */ PrefFile *prefs_read_open(const gchar *path) { PrefFile *pfile; FILE *fp; cm_return_val_if_fail(path != NULL, NULL); if ((fp = claws_fopen(path, "rb")) == NULL) { FILE_OP_ERROR(path, "claws_fopen"); return NULL; } pfile = g_new(PrefFile, 1); pfile->fp = fp; pfile->orig_fp = NULL; pfile->path = g_strdup(path); pfile->writing = FALSE; return pfile; } /*! *\brief Open preferences file for writing * Prefs are written to a temp file: Call prefs_file_close() * to rename this to the final filename * *\param path Filename with path of preferences file to write * *\return PrefFile * preferences file struct */ PrefFile *prefs_write_open(const gchar *path) { PrefFile *pfile; gchar *tmppath; FILE *fp; cm_return_val_if_fail(path != NULL, NULL); if (prefs_is_readonly(path)) { g_warning("no write permission on '%s'", path); return NULL; } tmppath = g_strconcat(path, ".tmp", NULL); if ((fp = claws_fopen(tmppath, "wb")) == NULL) { FILE_OP_ERROR(tmppath, "claws_fopen"); g_free(tmppath); return NULL; } if (change_file_mode_rw(fp, tmppath) < 0) FILE_OP_ERROR(tmppath, "chmod"); g_free(tmppath); pfile = g_new(PrefFile, 1); pfile->fp = fp; pfile->orig_fp = NULL; pfile->path = g_strdup(path); pfile->writing = TRUE; return pfile; } gboolean prefs_common_get_flush_metadata (void); /*! *\brief Close and free preferences file * Creates final file from temp, creates backup * *\param pfile Preferences file struct * *\return 0 on success, -1 on failure */ gint prefs_file_close(PrefFile *pfile) { FILE *fp, *orig_fp; gchar *path; gchar *tmppath; gchar *bakpath = NULL; gchar buf[BUFFSIZE]; cm_return_val_if_fail(pfile != NULL, -1); fp = pfile->fp; orig_fp = pfile->orig_fp; path = pfile->path; if (!pfile->writing) { claws_fclose(fp); g_free(pfile); g_free(path); return 0; } if (orig_fp) { while (claws_fgets(buf, sizeof(buf), orig_fp) != NULL) { /* next block */ if (buf[0] == '[') { if (claws_fputs(buf, fp) == EOF) { g_warning("failed to write configuration to file"); prefs_file_close_revert(pfile); return -1; } break; } } while (claws_fgets(buf, sizeof(buf), orig_fp) != NULL) if (claws_fputs(buf, fp) == EOF) { g_warning("failed to write configuration to file"); prefs_file_close_revert(pfile); return -1; } claws_fclose(orig_fp); } tmppath = g_strconcat(path, ".tmp", NULL); if (claws_safe_fclose(fp) == EOF) { FILE_OP_ERROR(tmppath, "claws_fclose"); claws_unlink(tmppath); g_free(path); g_free(tmppath); return -1; } if (is_file_exist(path)) { bakpath = g_strconcat(path, ".bak", NULL); #ifdef G_OS_WIN32 claws_unlink(bakpath); #endif if (g_rename(path, bakpath) < 0) { FILE_OP_ERROR(path, "rename"); claws_unlink(tmppath); g_free(path); g_free(tmppath); g_free(bakpath); return -1; } } #ifdef G_OS_WIN32 claws_unlink(path); #endif if (g_rename(tmppath, path) < 0) { FILE_OP_ERROR(tmppath, "rename"); claws_unlink(tmppath); g_free(path); g_free(tmppath); g_free(bakpath); return -1; } g_free(pfile); g_free(path); g_free(tmppath); g_free(bakpath); return 0; } /*! *\brief Close and free preferences file, delete temp file * *\param pfile Preferences file struct */ gint prefs_file_close_revert(PrefFile *pfile) { gchar *tmppath = NULL; cm_return_val_if_fail(pfile != NULL, -1); if (pfile->orig_fp) claws_fclose(pfile->orig_fp); if (pfile->writing) tmppath = g_strconcat(pfile->path, ".tmp", NULL); claws_fclose(pfile->fp); if (pfile->writing) { if (claws_unlink(tmppath) < 0) FILE_OP_ERROR(tmppath, "unlink"); g_free(tmppath); } g_free(pfile->path); g_free(pfile); return 0; } /*! *\brief Check if "path" is a file and readonly */ static gboolean prefs_is_readonly(const gchar * path) { if (path == NULL) return TRUE; return (access(path, W_OK) != 0 && access(path, F_OK) == 0); } /*! *\brief Check if "rcfile" is in rcdir, a file and readonly */ gboolean prefs_rc_is_readonly(const gchar * rcfile) { gboolean result; gchar * rcpath; if (rcfile == NULL) return TRUE; rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, rcfile, NULL); result = prefs_is_readonly(rcpath); g_free(rcpath); return result; } /*! *\brief Selects current section in preferences file * Creates section if file is written * *\param pfile Preferences file struct * *\return 0 on success, -1 on failure */ gint prefs_set_block_label(PrefFile *pfile, const gchar *label) { gchar *block_label; gchar buf[BUFFSIZE]; block_label = g_strdup_printf("[%s]", label); if (!pfile->writing) { while (claws_fgets(buf, sizeof(buf), pfile->fp) != NULL) { gint val; val = strncmp(buf, block_label, strlen(block_label)); if (val == 0) { debug_print("Found %s\n", block_label); break; } } } else { if ((pfile->orig_fp = claws_fopen(pfile->path, "rb")) != NULL) { gboolean block_matched = FALSE; while (claws_fgets(buf, sizeof(buf), pfile->orig_fp) != NULL) { gint val; val = strncmp(buf, block_label, strlen(block_label)); if (val == 0) { debug_print("Found %s\n", block_label); block_matched = TRUE; break; } else { if (claws_fputs(buf, pfile->fp) == EOF) { g_warning("failed to write configuration to file"); prefs_file_close_revert(pfile); g_free(block_label); return -1; } } } if (!block_matched) { claws_fclose(pfile->orig_fp); pfile->orig_fp = NULL; } } if (claws_fputs(block_label, pfile->fp) == EOF || claws_fputc('\n', pfile->fp) == EOF) { g_warning("failed to write configuration to file"); prefs_file_close_revert(pfile); g_free(block_label); return -1; } } g_free(block_label); return 0; }