Fixed fonts memory corruption for: --enable-bundle
[udpgate.git] / src / main.c
1 /* $Id$
2  * UDP Gateway utility
3  * Copyright (C) 2004 Jan Kratochvil <project-udpgate@jankratochvil.net>
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; exactly version 2 of June 1991 is required
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19
20 #include "config.h"
21
22 #include <glib/gmessages.h>
23 #include <popt.h>
24 #include <locale.h>
25 #include <stdlib.h>
26 #include <glib/gutils.h>
27 #include <string.h>
28 #include <setjmp.h>
29 #include <unistd.h>
30
31 #ifdef HAVE_GNOME
32 #include <libgnome/gnome-program.h>
33 #include <libgnomeui/gnome-ui-init.h>
34 #endif
35
36 #include "main.h"       /* self */
37 #include "ui-line.h"
38 #include "network.h"
39 #include "configuration.h"
40 #include "static-startup.h"
41 #ifdef ENABLE_BUNDLE
42 #include "bundle-util.h"
43 #endif
44
45 #ifdef HAVE_GNOME
46 #include "ui-gnome.h"
47 #endif
48
49
50 /* Config: */
51 #define LOCAL_PORT_DEFAULT 9201
52
53
54 static int optarg_text;
55 int optarg_verbose;
56 int optarg_port=LOCAL_PORT_DEFAULT;
57 static int optarg_start;
58 static int optarg_stop;
59 int optarg_no_fork;
60 static int optarg_startup_query;
61 static int optarg_startup_on;
62 static int optarg_startup_off;
63
64 void (*ui_interactive)(void);
65
66 static const struct poptOption popt_table[]={
67
68 #define UDPGATE_POPT(shortname,longname,argInfoP,argP,valP,descripP,argDescripP) \
69                 { \
70                         longName: (longname), \
71                         shortName: (shortname), \
72                         argInfo: (argInfoP)|(!(valP) ? 0 : POPT_ARG_VAL), \
73                         arg: (void *)argP, \
74                         val: (valP), \
75                         descrip: (descripP), \
76                         argDescrip: (argDescripP), \
77                 }
78
79 #ifdef HAVE_GNOME
80 #define OPT_TEXT_IF_GNOME N_("Disable Gnome UI; --text must be first argument")
81 #else /* HAVE_GNOME */
82 #define OPT_TEXT_IF_GNOME N_("(no Gnome UI compiled - stub only); --text must be first argument")
83 #endif /* HAVE_GNOME */
84                 UDPGATE_POPT(0  ,"text"         ,POPT_ARG_NONE                          ,&optarg_text         ,0,
85                                 OPT_TEXT_IF_GNOME,NULL),                                                                  
86 #undef OPT_TEXT_IF_GNOME                                                                          
87                 UDPGATE_POPT('v',"verbose"      ,POPT_ARG_NONE                          ,&optarg_verbose      ,0,
88                                 N_("Display additional debug information"),NULL),                                         
89                 UDPGATE_POPT('p',"port"         ,POPT_ARG_INT |POPT_ARGFLAG_SHOW_DEFAULT,&optarg_port         ,0,
90                                 N_("Listen on this UDP port"),NULL),                                                      
91                 UDPGATE_POPT('s',"start"        ,POPT_ARG_NONE                          ,&optarg_start        ,0,
92                                 N_("Start the daemon"),NULL),                                                             
93                 UDPGATE_POPT('S',"stop"         ,POPT_ARG_NONE                          ,&optarg_stop         ,0,
94                                 N_("Stop the daemon"),NULL),
95                 UDPGATE_POPT('1',"no-fork"      ,POPT_ARG_NONE                          ,&optarg_no_fork      ,0,
96                                 N_("Do not detach from the current process"),NULL),
97                 UDPGATE_POPT(0  ,"startup-query",POPT_ARG_NONE                          ,&optarg_startup_query,0,
98                                 N_("Query the current state of the system startup registrance"),NULL),
99                 UDPGATE_POPT(0  ,"startup-on"   ,POPT_ARG_NONE                          ,&optarg_startup_on   ,0,
100                                 N_("Register for the automatic system startup"),NULL),
101                 UDPGATE_POPT(0  ,"startup-off"  ,POPT_ARG_NONE                          ,&optarg_startup_off  ,0,
102                                 N_("Unregister from the automatic system startup"),NULL),
103
104 #undef UDPGATE_POPT
105                 POPT_TABLEEND
106                 };
107
108 static const struct poptOption popt_table_autohelp[]={
109                 { NULL,'\0',POPT_ARG_INCLUDE_TABLE,(struct poptOption *)&popt_table,0,PACKAGE },
110                 POPT_AUTOHELP
111                 POPT_TABLEEND
112                 };
113
114
115 #ifdef HAVE_GNOME
116 static jmp_buf gnome_init_atexit_jmpbuf;
117 static gboolean gnome_init_atexit_disable;
118
119 static void gnome_init_atexit_handler(void)
120 {
121         if (gnome_init_atexit_disable)
122                 return;
123
124         longjmp(gnome_init_atexit_jmpbuf,1);
125         g_assert_not_reached();
126         _exit(EXIT_FAILURE);
127 }
128
129 static gboolean gnome_init_g_log_handler_hit;
130 static void gnome_init_g_log_handler(const gchar *log_domain,GLogLevelFlags log_level,const gchar *message,gpointer user_data)
131 {
132         gnome_init_g_log_handler_hit=TRUE;
133         g_log_default_handler(log_domain,log_level,message,user_data);
134 }
135 #endif /* HAVE_GNOME */
136
137 static gchar *localedir;
138 #if defined(ENABLE_BUNDLE) && defined(HAVE_GNOME)
139 static const gchar *fonts_conf_dir;
140 #endif /* defined(ENABLE_BUNDLE) && defined(HAVE_GNOME) */
141
142 #ifdef ENABLE_BUNDLE
143 static void bundle_files_write(void)
144 {
145 gchar catalogs[]=G_STRINGIFY(CATALOGS);
146 gchar *catalog,*catalog_next;
147 #ifdef HAVE_GNOME
148 gchar fonts[]=G_STRINGIFY(GNOME_FONTS);
149 gchar *font,*font_next;
150 const gchar *fonts_data_dir,*fonts_conf_file,*fonts_conf_file_content;
151 #endif /* HAVE_GNOME */
152 const gchar *my_tmp_dir;
153
154         my_tmp_dir=udpgate_printf_alloca("%s/.%s-%s-%d",g_get_tmp_dir(),g_get_user_name(),PACKAGE,(int)getpid());
155
156         /* locale */
157         for (catalog=catalogs;*catalog;catalog=catalog_next) {
158 gchar *cc,*cc_end;
159
160                 for (catalog_next=catalog;*catalog_next && *catalog_next!=' ';catalog_next++);
161                 if (*catalog_next)
162                         *catalog_next++='\0';
163                 cc=g_strdup(catalog);
164                 cc_end=cc+strlen(cc)-strlen(".gmo");
165                 if (cc_end>cc && !strcmp(cc_end,".gmo")) {
166                         *cc_end='\0';
167                         if (!bundle_util_file_write(
168                                         udpgate_printf_alloca("%s/%s/LC_MESSAGES/%s.mo",LOCALEDIR,cc,PACKAGE),  /* pathname */
169                                         catalog,        /* basename */
170                                         0644,   /* pathname_mode */
171                                         BUNDLE_UTIL_MKDIRS_MASK|BUNDLE_UTIL_TEMPORARY_MASK)) {  /* flags */
172 gchar *trylocaledir;
173
174                                 trylocaledir=localedir;
175                                 if (!trylocaledir)
176                                         trylocaledir=g_strdup_printf("%s/locale",my_tmp_dir);
177                                 if (bundle_util_file_write(
178                                                 udpgate_printf_alloca("%s/%s/LC_MESSAGES/%s.mo",trylocaledir,cc,PACKAGE),       /* pathname */
179                                                 catalog,        /* basename */
180                                                 0644,   /* pathname_mode */
181                                                 BUNDLE_UTIL_MKDIRS_MASK|BUNDLE_UTIL_TEMPORARY_MASK))    /* flags */
182                                         localedir=trylocaledir;
183                                 else
184                                         g_free(trylocaledir);
185                                 }
186
187                         }
188                 g_free(cc);
189                 }
190
191 #ifdef HAVE_GNOME
192         /* Gnome */
193         fonts_conf_dir=g_strdup_printf("%s/fonts",my_tmp_dir);
194         fonts_data_dir=udpgate_printf_alloca("%s/fonts-data",my_tmp_dir);
195         fonts_conf_file=udpgate_printf_alloca("%s/fonts.conf",fonts_conf_dir);
196
197         fonts_conf_file_content=udpgate_printf_alloca("\
198 <?xml version=\"1.0\"?>\n\
199 <!DOCTYPE fontconfig SYSTEM \"fonts.dtd\">\n\
200 <fontconfig>\n\
201 \t<dir>%s</dir>\n\
202 </fontconfig>\n\
203 ",fonts_data_dir);
204         bundle_util_file_insert(fonts_conf_file_content,strlen(fonts_conf_file_content),"fonts.conf");
205
206         if (bundle_util_file_write(
207                         fonts_conf_file,        /* pathname */
208                         "fonts.conf",   /* basename */
209                         0644,   /* pathname_mode */
210                         BUNDLE_UTIL_MKDIRS_MASK|BUNDLE_UTIL_TEMPORARY_MASK)) {  /* flags */
211                 for (font=fonts;*font;font=font_next) {
212                         for (font_next=font;*font_next && *font_next!=' ';font_next++);
213                         if (*font_next)
214                                 *font_next++='\0';
215
216                         /* errors ignored */
217                         bundle_util_file_write(
218                                         udpgate_printf_alloca("%s/%s",fonts_data_dir,font),     /* pathname */
219                                         font,   /* basename */
220                                         0644,   /* pathname_mode */
221                                         BUNDLE_UTIL_MKDIRS_MASK|BUNDLE_UTIL_TEMPORARY_MASK);    /* flags */
222                         }
223                 }
224 #endif /* HAVE_GNOME */
225 }
226 #endif /* ENABLE_BUNDLE */
227
228 int main(int argc,char **argv)
229 {
230 poptContext context;
231 int errint;
232 gboolean is_interactive;
233 #ifdef HAVE_GNOME
234 gboolean no_gnome;
235 #endif /* HAVE_GNOME */
236 int exit_rc=EXIT_SUCCESS;
237
238 #ifdef ENABLE_BUNDLE
239         bundle_files_write();
240
241 #ifdef HAVE_GNOME
242         /* Prevent fontconfig loading: /etc/fonts/fonts.conf */
243         /* 'fonts_conf_dir' is created by: bundle_files_write() */
244         setenv("FONTCONFIG_PATH",fonts_conf_dir,
245                         1);     /* overwrite */
246 #endif /* HAVE_GNOME */
247 #endif /* ENABLE_BUNDLE */
248
249 #if 0
250         g_log_set_always_fatal(~(0
251                         |G_LOG_LEVEL_MESSAGE
252                         |G_LOG_LEVEL_INFO
253                         |G_LOG_LEVEL_DEBUG
254                         ));
255         setenv("GNOME_DISABLE_CRASH_DIALOG","1",1);     /* HAVE_GNOME */
256 #endif /* 0 */
257
258         /* Initialize the i18n stuff */
259         setlocale(LC_ALL,"");
260         if (!localedir)
261                 localedir=LOCALEDIR;
262         bindtextdomain(PACKAGE,localedir);
263         textdomain(PACKAGE);
264
265         /* Read it before the command-line parsing to get the default value
266          * of 'optarg_port' displayable by 'POPT_ARGFLAG_SHOW_DEFAULT'.
267          */
268         configuration_read();
269
270         if (argv[1] && !strcmp(argv[1],"--text"))
271                 optarg_text=1;
272
273 #ifdef HAVE_GNOME
274         no_gnome=(optarg_text || !getenv("DISPLAY") || !*getenv("DISPLAY"));
275
276         if (no_gnome)
277 #endif /* HAVE_GNOME */
278         {
279                 context=poptGetContext(
280                                 PACKAGE,        /* name */
281                                 argc,(/*en-const*/const char **)argv,   /* argc,argv */
282                                 popt_table_autohelp,    /* options */
283                                 POPT_CONTEXT_POSIXMEHARDER);    /* flags; && !POPT_CONTEXT_KEEP_FIRST */
284                 if (context==NULL) {
285                         g_assert_not_reached(); /* argument recognization args_error */
286                         return EXIT_FAILURE;
287                         }
288                 errint=poptReadDefaultConfig(context,
289                                 TRUE);  /* useEnv */
290                 if (errint!=0) {
291                         g_assert_not_reached(); /* argument recognization args_error */
292                         return EXIT_FAILURE;
293                         }
294                 errint=poptGetNextOpt(context);
295                 if (errint!=-1)
296                         g_error(_("Specified option not expected"));
297                 if (poptPeekArg(context))
298                         g_error(_("No arguments expected"));
299                 }
300 #ifdef HAVE_GNOME
301         else {
302 GnomeProgram *gnome_program;
303 guint handler_id;
304
305                 gnome_init_atexit_disable=FALSE;
306                 g_atexit(gnome_init_atexit_handler);
307                 gnome_init_g_log_handler_hit=FALSE;
308                 handler_id=g_log_set_handler(
309                                 "Gtk",  /* log_domain */
310                                 G_LOG_LEVEL_WARNING,    /* log_levels */
311                                 gnome_init_g_log_handler,       /* log_func */
312                                 NULL);  /* user_data */
313                 if (!setjmp(gnome_init_atexit_jmpbuf))
314                         gnome_program=gnome_program_init(PACKAGE,VERSION,LIBGNOMEUI_MODULE,argc,argv,
315                                         GNOME_PARAM_POPT_TABLE,popt_table,
316                                         GNOME_PARAM_POPT_FLAGS,(int)POPT_CONTEXT_POSIXMEHARDER,
317                                         NULL);
318                 else {
319                         no_gnome=TRUE;
320                         /* No message: (udpgate:3693): Gtk-WARNING **: cannot open display:
321                          * was reported, probably only '--help' message was shown.
322                          */
323                         if (!gnome_init_g_log_handler_hit)
324                                 exit(EXIT_SUCCESS);
325                         }
326                 gnome_init_atexit_disable=TRUE;
327                 g_log_remove_handler(
328                                 "Gtk",  /* log_domain */
329                                 handler_id);    /* handler_id */
330                 }
331 #endif /* HAVE_GNOME */
332
333         configuration_write();
334
335         is_interactive=(1
336                         && !optarg_start
337                         && !optarg_stop
338                         && !optarg_startup_query
339                         && !optarg_startup_on
340                         && !optarg_startup_off);
341
342         /* Initialize UI here to catch all GLog errors below. */
343         if (is_interactive
344 #ifdef HAVE_GNOME
345                         && (no_gnome || !ui_gnome_init())
346 #endif /* HAVE_GNOME */
347                         && !ui_line_init())
348                 g_error(_("No UI interface could be initialized"));
349
350         if (!is_interactive) {
351
352                 if (optarg_stop)
353                         if (!network_stop())
354                                 exit_rc=2;
355                 if (optarg_startup_query) {
356 gboolean is_on;
357
358                         if (static_startup_query(&is_on)) {
359                                 g_message((is_on
360                                                 ? _("System startup registrance is turned on.")
361                                                 : _("System startup registrance is turned off.")));
362                                 if (exit_rc<2)
363                                         exit_rc=(is_on ? 0 : 1);
364                                 }
365                         else
366                                 exit_rc=2;
367                         }
368                 if (optarg_startup_off) {
369                         if (!static_startup_off())
370                                 exit_rc=2;
371                         }
372                 if (optarg_startup_on) {
373                         if (!static_startup_on())
374                                 exit_rc=2;
375                         }
376                 if (optarg_start)
377                         if (!network_start(optarg_port))
378                                 exit_rc=2;
379
380                 network_detach();
381                 }
382         else
383                 (*ui_interactive)();
384
385         configuration_write();
386
387         exit(exit_rc);
388 }