Updated Spanish translation
[gnome-utils.git] / logview / logview-app.c
blobf861b82b85672ab0811014c52068683c8cdff956
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2 /* logview-app.c - logview application singleton
4 * Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* logview-app.c */
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include "logview-app.h"
29 #include "logview-manager.h"
30 #include "logview-window.h"
31 #include "logview-prefs.h"
33 #include <glib/gi18n.h>
35 struct _LogviewAppPrivate {
36 LogviewPrefs *prefs;
37 LogviewManager *manager;
38 LogviewWindow *window;
41 enum {
42 APP_QUIT,
43 LAST_SIGNAL
46 static guint signals[LAST_SIGNAL] = { 0 };
48 static LogviewApp *app_singleton = NULL;
50 G_DEFINE_TYPE (LogviewApp, logview_app, G_TYPE_OBJECT);
52 #define GET_PRIVATE(o) \
53 (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_APP, LogviewAppPrivate))
55 static gboolean
56 main_window_delete_cb (GtkWidget *widget,
57 GdkEvent *event,
58 gpointer user_data)
60 LogviewApp *app = user_data;
62 g_signal_emit (app, signals[APP_QUIT], 0, NULL);
64 return FALSE;
67 static gboolean
68 logview_app_set_window (LogviewApp *app)
70 LogviewWindow *window;
71 gboolean retval = FALSE;
73 window = LOGVIEW_WINDOW (logview_window_new ());
75 if (window) {
76 app->priv->window = window;
77 g_signal_connect (window, "delete-event",
78 G_CALLBACK (main_window_delete_cb), app);
79 retval = TRUE;
82 gtk_window_set_default_icon_name ("logview");
84 return retval;
87 typedef struct {
88 LogviewApp *app;
89 GSList *logs;
90 } EnumerateJob;
92 /* TODO: ideally we should parse configuration files in /etc/logrotate.conf
93 * and all the files in /etc/logrotate.d/ and group all the logs referring
94 * to the same entry under a category. Right now, we just do some
95 * parsing instead, and fill with quasi-sensible defaults.
98 /* adapted from sysklogd sources */
99 static GSList*
100 parse_syslog ()
102 char cbuf[BUFSIZ];
103 char *cline, *p;
104 FILE *cf;
105 GSList *logfiles = NULL;
107 if ((cf = fopen ("/etc/syslog.conf", "r")) == NULL) {
108 return NULL;
111 cline = cbuf;
112 while (fgets (cline, sizeof (cbuf) - (cline - cbuf), cf) != NULL) {
113 gchar **list;
114 gint i;
116 for (p = cline; g_ascii_isspace (*p); ++p);
117 if (*p == '\0' || *p == '#' || *p == '\n')
118 continue;
120 list = g_strsplit_set (p, ", -\t()\n", 0);
122 for (i = 0; list[i]; ++i) {
123 if (*list[i] == '/' &&
124 g_slist_find_custom (logfiles, list[i],
125 (GCompareFunc) g_ascii_strcasecmp) == NULL)
127 logfiles = g_slist_insert (logfiles,
128 g_strdup (list[i]), 0);
132 g_strfreev (list);
135 fclose (cf);
137 return logfiles;
140 static void
141 enumerate_job_finish (EnumerateJob *job)
143 GSList *files = job->logs;
144 LogviewApp *app = job->app;
146 logview_manager_add_logs_from_name_list (app->priv->manager, files, files->data);
148 g_slist_foreach (files, (GFunc) g_free, NULL);
149 g_slist_free (files);
151 g_object_unref (job->app);
152 g_slice_free (EnumerateJob, job);
155 static void
156 enumerate_next_files_async_cb (GObject *source,
157 GAsyncResult *res,
158 gpointer user_data)
160 EnumerateJob *job = user_data;
161 GList *enumerated_files, *l;
162 GFileInfo *info;
163 GSList *logs;
164 const char *content_type, *name;
165 char *parse_string, *container_path;
166 GFileType type;
167 GFile *container;
169 enumerated_files = g_file_enumerator_next_files_finish (G_FILE_ENUMERATOR (source),
170 res, NULL);
171 if (!enumerated_files) {
172 enumerate_job_finish (job);
173 return;
176 logs = job->logs;
177 container = g_file_enumerator_get_container (G_FILE_ENUMERATOR (source));
178 container_path = g_file_get_path (container);
180 /* TODO: we don't support grouping rotated logs yet, skip gzipped files
181 * and those which name contains a formatted date.
183 for (l = enumerated_files; l; l = l->next) {
184 info = l->data;
185 type = g_file_info_get_file_type (info);
186 content_type = g_file_info_get_content_type (info);
187 name = g_file_info_get_name (info);
189 if (!g_file_info_get_attribute_boolean (info, "access::can-read")) {
190 g_object_unref (info);
191 continue;
194 if (type != (G_FILE_TYPE_REGULAR || G_FILE_TYPE_SYMBOLIC_LINK) ||
195 !g_content_type_is_a (content_type, "text/plain"))
197 g_object_unref (info);
198 continue;
201 if (g_content_type_is_a (content_type, "application/x-gzip")) {
202 g_object_unref (info);
203 continue;
206 if (g_regex_match_simple ("\\d{8}$", name, 0, 0)) {
207 g_object_unref (info);
208 continue;
211 parse_string = g_build_filename (container_path, name, NULL);
213 if (g_slist_find_custom (logs, parse_string, (GCompareFunc) g_ascii_strcasecmp) == NULL) {
214 logs = g_slist_append (logs, parse_string);
215 } else {
216 g_free (parse_string);
219 g_object_unref (info);
220 parse_string = NULL;
223 g_list_free (enumerated_files);
224 g_object_unref (container);
225 g_free (container_path);
227 job->logs = logs;
229 enumerate_job_finish (job);
232 static void
233 enumerate_children_async_cb (GObject *source,
234 GAsyncResult *res,
235 gpointer user_data)
237 EnumerateJob *job = user_data;
238 GFileEnumerator *enumerator;
240 enumerator = g_file_enumerate_children_finish (G_FILE (source),
241 res, NULL);
242 if (!enumerator) {
243 enumerate_job_finish (job);
244 return;
247 g_file_enumerator_next_files_async (enumerator, G_MAXINT,
248 G_PRIORITY_DEFAULT,
249 NULL, enumerate_next_files_async_cb, job);
252 static void
253 logview_app_first_time_initialize (LogviewApp *app)
255 GSList *logs;
256 GFile *log_dir;
257 EnumerateJob *job;
259 /* let's add all accessible files in /var/log and those mentioned
260 * in /etc/syslog.conf.
263 logs = parse_syslog ();
265 job = g_slice_new0 (EnumerateJob);
266 job->app = g_object_ref (app);
267 job->logs = logs;
269 log_dir = g_file_new_for_path ("/var/log/");
270 g_file_enumerate_children_async (log_dir,
271 "standard::*,access::can-read", 0,
272 G_PRIORITY_DEFAULT, NULL,
273 enumerate_children_async_cb, job);
275 g_object_unref (log_dir);
278 static void
279 do_finalize (GObject *obj)
281 LogviewApp *app = LOGVIEW_APP (obj);
283 g_object_unref (app->priv->manager);
284 g_object_unref (app->priv->prefs);
286 G_OBJECT_CLASS (logview_app_parent_class)->finalize (obj);
289 static void
290 logview_app_class_init (LogviewAppClass *klass)
292 GObjectClass *oclass = G_OBJECT_CLASS (klass);
294 oclass->finalize = do_finalize;
296 signals[APP_QUIT] =
297 g_signal_new ("app-quit",
298 G_OBJECT_CLASS_TYPE (oclass),
299 G_SIGNAL_RUN_LAST,
300 G_STRUCT_OFFSET (LogviewAppClass, app_quit),
301 NULL, NULL,
302 g_cclosure_marshal_VOID__VOID,
303 G_TYPE_NONE, 0);
305 g_type_class_add_private (klass, sizeof (LogviewAppPrivate));
308 static void
309 logview_app_init (LogviewApp *self)
311 LogviewAppPrivate *priv = self->priv = GET_PRIVATE (self);
313 priv->prefs = logview_prefs_get ();
314 priv->manager = logview_manager_get ();
317 LogviewApp*
318 logview_app_get (void)
320 if (!app_singleton) {
321 app_singleton = g_object_new (LOGVIEW_TYPE_APP, NULL);
323 if (!logview_app_set_window (app_singleton)) {
324 g_object_unref (app_singleton);
325 app_singleton = NULL;
329 return app_singleton;
332 void
333 logview_app_initialize (LogviewApp *app, char **log_files)
335 LogviewAppPrivate *priv;
337 g_assert (LOGVIEW_IS_APP (app));
339 priv = app->priv;
341 /* open regular logs and add each log passed as a parameter */
343 if (log_files == NULL) {
344 char *active_log;
345 gchar **logs;
347 active_log = logview_prefs_get_active_logfile (priv->prefs);
348 logs = logview_prefs_get_stored_logfiles (priv->prefs);
350 if (!logs) {
351 logview_app_first_time_initialize (app);
352 } else {
353 logview_manager_add_logs_from_names (priv->manager,
354 logs, active_log);
356 g_free (active_log);
357 g_strfreev (logs);
359 } else {
360 logview_manager_add_logs_from_names (priv->manager, log_files, NULL);
363 gtk_widget_show (GTK_WIDGET (priv->window));
366 void
367 logview_app_add_error (LogviewApp *app,
368 const char *file_path,
369 const char *secondary)
371 LogviewWindow *window;
372 char *primary;
374 g_assert (LOGVIEW_IS_APP (app));
376 window = app->priv->window;
377 primary = g_strdup_printf (_("Impossible to open the file %s"), file_path);
379 logview_window_add_error (window, primary, secondary);
381 g_free (primary);
384 void
385 logview_app_add_errors (LogviewApp *app,
386 GPtrArray *errors)
388 LogviewWindow *window;
390 g_assert (LOGVIEW_IS_APP (app));
392 window = app->priv->window;
394 if (errors->len == 0) {
395 return;
396 } else if (errors->len == 1) {
397 char **err;
399 err = g_ptr_array_index (errors, 0);
400 logview_window_add_error (window, err[0], err[1]);
401 } else {
402 logview_window_add_errors (window, errors);