1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3 * Pan - A Newsreader for Gtk+
4 * Copyright (C) 2002-2006 Charles Kerr <charles@rebelbase.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #include <config.h>
21 #include <cerrno>
22 #include <cstdio>
23 #include <map>
24 #include <iostream>
25 #include <fstream>
26 extern "C" {
27 #include <sys/types.h> // for chmod
28 #include <sys/stat.h> // for chmod
29 #include <unistd.h>
30 #include <glib.h>
31 #include <glib/gi18n.h>
32 }
33 #include <pan/general/debug.h>
34 #include <pan/general/file-util.h>
35 #include <pan/general/line-reader.h>
36 #include <pan/general/log.h>
37 #include "data-io.h"
38
39 using namespace pan;
40
41 namespace
42 {
get_pan_home_file(const char * fname)43 std::string get_pan_home_file (const char * fname)
44 {
45 const std::string home (file::get_pan_home());
46 char * filename (g_build_filename (home.c_str(), fname, NULL));
47 std::string retval (filename);
48 g_free (filename);
49 return retval;
50 }
51
get_tasks_filename()52 std::string get_tasks_filename ()
53 {
54 return get_pan_home_file ("tasks.nzb");
55 }
56
get_group_descriptions_filename()57 std::string get_group_descriptions_filename ()
58 {
59 return get_pan_home_file ("newsgroups.dsc");
60 }
61
get_group_permissions_filename()62 std::string get_group_permissions_filename ()
63 {
64 return get_pan_home_file ("newsgroups.ynm");
65 }
66
get_group_xovers_filename()67 std::string get_group_xovers_filename ()
68 {
69 return get_pan_home_file ("newsgroups.xov");
70 }
71
get_group_headers_filename(const Quark & group)72 std::string get_group_headers_filename (const Quark& group)
73 {
74 const std::string home (file::get_pan_home());
75 char * filename (g_build_filename (home.c_str(), "groups", group.c_str(), NULL));
76 char * dirname (g_path_get_dirname (filename));
77 file :: ensure_dir_exists (dirname);
78 std::string retval (filename);
79 g_free (dirname);
80 g_free (filename);
81 return retval;
82 }
83
get_download_stats_filename()84 std::string get_download_stats_filename ()
85 {
86 return get_pan_home_file ("downloads.stats");
87 }
88
89 }
90
91 std::string
get_scorefile_name() const92 DataIO :: get_scorefile_name () const
93 {
94 std::string s;
95
96 const char * env_str (g_getenv ("SCOREFILE"));
97 if (env_str && *env_str)
98 s = env_str;
99
100 if (s.empty()) {
101 char * path (g_build_filename (g_get_home_dir(), "News", "Score", NULL));
102 if (file :: file_exists (path))
103 s = path;
104 g_free (path);
105 }
106
107 if (s.empty())
108 s = get_pan_home_file ("Score");
109
110 return s;
111 }
112
113 std::string
get_posting_name() const114 DataIO :: get_posting_name () const
115 {
116 return get_pan_home_file ("posting.xml");
117 }
118
119 std::string
get_server_filename() const120 DataIO :: get_server_filename () const
121 {
122 return get_pan_home_file ("servers.xml");
123 }
124
125 /****
126 *****
127 ****/
128
129 void
clear_group_headers(const Quark & group)130 DataIO :: clear_group_headers (const Quark& group)
131 {
132 const std::string filename (get_group_headers_filename (group));
133 std::remove (filename.c_str());
134 }
135
136 /****
137 *****
138 ****/
139
140 LineReader*
read_tasks() const141 DataIO :: read_tasks () const
142 {
143 const std::string filename (get_tasks_filename ());
144 return file::file_exists(filename.c_str()) ? read_file(filename) : 0;
145 }
146
147 LineReader*
read_group_descriptions() const148 DataIO :: read_group_descriptions () const
149 {
150 return read_file (get_group_descriptions_filename ());
151 }
152
153 LineReader*
read_group_permissions() const154 DataIO :: read_group_permissions () const
155 {
156 return read_file (get_group_permissions_filename ());
157 }
158
159 LineReader*
read_download_stats() const160 DataIO :: read_download_stats () const
161 {
162 return read_file (get_download_stats_filename ());
163 }
164
165 LineReader*
read_group_xovers() const166 DataIO :: read_group_xovers () const
167 {
168 return read_file (get_group_xovers_filename ());
169 }
170
171 LineReader*
read_group_headers(const Quark & group) const172 DataIO :: read_group_headers (const Quark& group) const
173 {
174 const std::string filename (get_group_headers_filename (group));
175 return file::file_exists(filename.c_str()) ? read_file(filename) : 0;
176 }
177
178 LineReader*
read_file(const StringView & filename) const179 DataIO :: read_file (const StringView& filename) const
180 {
181 return new FileLineReader (filename);
182 }
183
184 /****
185 *****
186 ****/
187
188 namespace
189 {
190 std::map<std::ofstream*, std::string> ostream_to_filename;
191
get_ostream(const std::string filename)192 std::ostream* get_ostream (const std::string filename)
193 {
194 const std::string tmp (filename + ".tmp");
195 std::ofstream * o (new std::ofstream (
196 tmp.c_str(), std::ios_base::out|std::ios_base::binary));
197
198 if (!o->good())
199 Log::add_err_va (_("Unable to save “%s” %s"), filename.c_str(), "");
200 ostream_to_filename[o] = filename;
201 return o;
202 }
203
finalize_ostream(std::ofstream * o)204 void finalize_ostream (std::ofstream * o)
205 {
206 g_assert (ostream_to_filename.count(o));
207 const std::string filename (ostream_to_filename[o]);
208 ostream_to_filename.erase (o);
209
210 o->flush ();
211 const bool ok = !o->fail();
212 const int my_errno = errno;
213 delete o;
214
215 const std::string tmpfile (filename + ".tmp");
216 if (ok) {
217 #if defined(G_OS_WIN32)
218 ::remove (filename.c_str());
219 #endif
220 int ret = 0;
221 if ((ret = rename (tmpfile.c_str(), filename.c_str())))
222 {
223 std::cerr << LINE_ID << " ERROR renaming from [" << tmpfile << "] to [" << filename << "]: " << g_strerror(errno) <<" : "<<ret<< '\n';
224 } else
225 {
226 if ((ret = chmod (filename.c_str(), 0600)))
227 std::cerr << LINE_ID << " ERROR chmodding [" << filename << "]: " << g_strerror(errno) << " : "<<ret<<'\n';
228 }
229 // std::cerr<<"dbg "<<ret<<"\n";
230 } else {
231 Log::add_err_va (_("Unable to save “%s” %s"), filename.c_str(), file::pan_strerror(my_errno));
232 }
233 }
234 }
235
236 std::ostream*
write_tasks()237 DataIO :: write_tasks ()
238 {
239 return write_file (get_tasks_filename ());
240 }
241
242 std::ostream*
write_server_properties()243 DataIO :: write_server_properties ()
244 {
245 return write_file (get_server_filename());
246 }
247
248 std::ostream*
write_group_xovers()249 DataIO :: write_group_xovers ()
250 {
251 return write_file (get_group_xovers_filename ());
252 }
253
254 std::ostream*
write_group_descriptions()255 DataIO :: write_group_descriptions ()
256 {
257 return write_file (get_group_descriptions_filename ());
258 }
259
260 std::ostream*
write_group_permissions()261 DataIO :: write_group_permissions ()
262 {
263 return write_file (get_group_permissions_filename ());
264 }
265
266 std::ostream*
write_group_headers(const Quark & group)267 DataIO :: write_group_headers (const Quark& group)
268 {
269 return write_file (get_group_headers_filename (group));
270 }
271
272 std::ostream*
write_download_stats()273 DataIO :: write_download_stats ()
274 {
275 return write_file (get_download_stats_filename ());
276 }
277
278 std::ostream*
write_file(const StringView & filename)279 DataIO :: write_file (const StringView& filename)
280 {
281 return get_ostream (filename);
282 }
283
284 void
write_done(std::ostream * out)285 DataIO :: write_done (std::ostream* out)
286 {
287 finalize_ostream (dynamic_cast<std::ofstream*>(out));
288 }
289