/*
* Claws Mail -- 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 read-only
*/
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 read-only
*/
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 and pfile is freed.
*/
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;
}