1 /****************************************************************************
2  *
3  * Copyright (c) 1999 Sasha Vasko <sasha at aftercode.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; either version 2 of the License, or
8  * (at your option) any later version.
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, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  ****************************************************************************/
20 
21 #define LOCAL_DEBUG
22 #include "../configure.h"
23 
24 #include <stdarg.h>
25 #include <string.h>
26 #include <signal.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 
30 #include "asapp.h"
31 #include "afterstep.h"
32 #include "parser.h"
33 #include "screen.h"
34 #include "functions.h"
35 #include "session.h"
36 #include "balloon.h"
37 #include "mystyle.h"
38 #include "mylook.h"
39 #include "wmprops.h"
40 #include "desktop_category.h"
41 #include "../libAfterImage/asimage.h"
42 #include "../libAfterImage/xpm.h"
43 #include "../libAfterImage/char2uni.h"
44 
45 
46 ASProgArgs as_app_args = { 0, NULL, 0, NULL, NULL, NULL, 0, 0 };	/* some typical progy cmd line options - set by SetMyArgs( argc, argv ) */
47 
48 ASProgArgs *MyArgsPtr = &as_app_args;
49 char *MyName = NULL;						/* name are we known by */
50 char MyClass[MAX_MY_CLASS + 1] = "unknown";	/* application Class name ( Pager, Wharf, etc. ) - set by SetMyClass(char *) */
51 void (*MyVersionFunc) (void) = NULL;
52 void (*MyUsageFunc) (void) = NULL;
53 
54 char *as_afterstep_dir_name = AFTER_DIR;
55 char *as_save_dir_name = AFTER_DIR "/" AFTER_SAVE;
56 char *as_start_dir_name = AFTER_DIR "/" START_DIR;
57 char *as_share_dir_name = AFTER_SHAREDIR;
58 
59 char *as_background_dir_name = BACK_DIR;
60 char *as_look_dir_name = LOOK_DIR;
61 char *as_theme_dir_name = THEME_DIR;
62 char *as_theme_file_dir_name = THEME_FILE_DIR;
63 char *as_feel_dir_name = FEEL_DIR;
64 char *as_colorscheme_dir_name = COLORSCHEME_DIR;
65 char *as_font_dir_name = FONT_DIR;
66 char *as_icon_dir_name = ICON_DIR;
67 char *as_tile_dir_name = TILE_DIR;
68 
69 
70 int fd_width;
71 
72 unsigned int nonlock_mods = 0;	/* a mask for non-locking modifiers */
73 unsigned int lock_mods[MAX_LOCK_MODS] = { 0 };	/* all combinations of lock modifier masks */
74 
75 /* Now for each display we may have one or several screens ; */
76 Display *dpy = NULL;
77 ScreenInfo *ASDefaultScr;				/* ScreenInfo for the default screen */
78 
79 //#define Scr   (*DefaultScr);
80 int x_fd = 0;										/* descriptor of the X Windows connection  */
81 
82 
83 int SingleScreen = -1;					/* if >= 0 then [points to the only ScreenInfo structure available */
84 int PointerScreen = 0;					/* screen that currently has pointer */
85 unsigned int NumberOfScreens = 0;	/* number of screens on display */
86 
87 /* unused - future development : */
88 ScreenInfo **all_screens = NULL;	/* all ScreenInfo structures for NumberOfScreens screens */
89 ASHashTable *screens_window_hash = NULL;	/* so we can easily track what window is on what screen */
90 
91 /* end of: unused - future development : */
92 
93 
94 struct ASFeel *DefaultFeel = NULL;	/* unused - future development : */
95 struct MyLook *DefaultLook = NULL;	/* unused - future development : */
96 
97 void (*CloseOnExec) () = NULL;
98 
99 struct ASSession *Session = NULL;	/* filenames of look, feel and background */
100 struct ASEnvironment *Environment = NULL;
101 
102 struct ASDatabase *Database = NULL;
103 
104 struct ASCategoryTree *StandardCategories = NULL;
105 struct ASCategoryTree *AfterStepCategories = NULL;
106 struct ASCategoryTree *KDECategories = NULL;
107 struct ASCategoryTree *GNOMECategories = NULL;
108 struct ASCategoryTree *OtherCategories = NULL;
109 struct ASCategoryTree *CombinedCategories = NULL;
110 
111 
112 
113 /* names of AS functions - used all over the place  :*/
114 
115 #define FUNC_TERM(keyword,func)         {TF_NO_MYNAME_PREPENDING|TF_NAMED,keyword,sizeof(keyword)-1,TT_FUNCTION,func,NULL}
116 #define FUNC_TERM2(flags,keyword,func)  {TF_NO_MYNAME_PREPENDING|TF_NAMED|(flags),keyword,sizeof(keyword)-1,TT_FUNCTION,func,NULL}
117 
118 TermDef FuncTerms[F_FUNCTIONS_NUM + 1] = {
119 	FUNC_TERM2 (NEED_NAME, "Nop", F_NOP),	/* Nop      "name"|"" */
120 	FUNC_TERM2 (NEED_NAME, "Title", F_TITLE),	/* Title    "name"    */
121 	FUNC_TERM ("Beep", F_BEEP),		/* Beep               */
122 	FUNC_TERM ("Quit", F_QUIT),		/* Quit     ["name"] */
123 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "Restart", F_RESTART),	/* Restart "name" WindowManagerName */
124 	FUNC_TERM ("SystemShutdown", F_SYSTEM_SHUTDOWN),	/* Shutdown "name" | only available under gnome-session */
125 	FUNC_TERM ("Logout", F_LOGOUT),	/* Logout "name" | only available under gnome-session */
126 	FUNC_TERM ("QuitWM", F_QUIT_WM),	/* Will only work when not running under gnome-session */
127 	FUNC_TERM ("Suspend", F_SUSPEND),	/* If provided by UPower */
128 	FUNC_TERM ("Hibernate", F_HIBERNATE),	/* If provided by UPower */
129 
130 	FUNC_TERM ("Refresh", F_REFRESH),	/* Refresh  ["name"] */
131 #ifndef NO_VIRTUAL
132 	FUNC_TERM2 (USES_NUMVALS, "Scroll", F_SCROLL),	/* Scroll     horiz vert */
133 	FUNC_TERM2 (USES_NUMVALS, "GotoPage", F_GOTO_PAGE),	/* GotoPage   x     y    */
134 	FUNC_TERM ("TogglePage", F_TOGGLE_PAGE),	/* TogglePage ["name"]   */
135 #endif
136 	FUNC_TERM2 (USES_NUMVALS, "CursorMove", F_MOVECURSOR),	/* CursorMove horiz vert */
137 	FUNC_TERM2 (NEED_WINIFNAME, "WarpFore", F_WARP_F),	/* WarpFore ["name" window_name] */
138 	FUNC_TERM2 (NEED_WINIFNAME, "WarpBack", F_WARP_B),	/* WarpBack ["name" window_name] */
139 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "Wait", F_WAIT),	/* Wait      "name" attributes  */
140 	FUNC_TERM2 (USES_NUMVALS, "Desk", F_DESK),	/* Desk arg1 [arg2] */
141 	FUNC_TERM2 (USES_NUMVALS, "GotoDeskViewport", F_GOTO_DESKVIEWPORT),	/* GotoDeskViewport DESK+VX+VY */
142 #ifndef NO_WINDOWLIST
143 	FUNC_TERM2 (USES_NUMVALS, "WindowList", F_WINDOWLIST),	/* WindowList [arg1 arg2] */
144 #endif
145 	FUNC_TERM ("StopModuleList", F_STOPMODULELIST),	/* StopModuleList "name" */
146 	FUNC_TERM ("RestartModuleList", F_RESTARTMODULELIST),	/* RestartModuleList "name" */
147 	FUNC_TERM2 (NEED_NAME, "PopUp", F_POPUP),	/* PopUp    "popup_name" [popup_name] */
148 	FUNC_TERM2 (NEED_NAME, "Function", F_FUNCTION),	/* Function "function_name" [function_name] */
149 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "Category", F_CATEGORY),	/* Category "function_name" category_name */
150 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "CategoryTree", F_CATEGORY_TREE),	/* CategoryTree "function_name" category_name */
151 	FUNC_TERM ("MiniPixmap", F_MINIPIXMAP),	/* MiniPixmap "name" */
152 	FUNC_TERM ("SmallMiniPixmap", F_SMALL_MINIPIXMAP),	/* SmallMiniPixmap "name" */
153 	FUNC_TERM ("LargeMiniPixmap", F_SMALL_MINIPIXMAP),	/* LargeMiniPixmap "name" */
154 	FUNC_TERM ("Preview", F_Preview),	/* Preview "name" */
155 	FUNC_TERM2 (NEED_NAME, "DesktopEntry", F_DesktopEntry),	/* DesktopEntry "name" */
156 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "Exec", F_EXEC),	/* Exec   "name" command */
157 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "ExecInDir", F_ExecInDir),	/* Exec   "name" [path command] */
158 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "Module", F_MODULE),	/* Module "name" command */
159 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "ExecInTerm", F_ExecInTerm),	/* ExecInTerm   "name" command */
160 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "ExecBrowser", F_ExecBrowser),	/* ExecBrowser   "name" url */
161 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "ExecEditor", F_ExecEditor),	/* ExecEditor   "name" filename */
162 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "KillModuleByName", F_KILLMODULEBYNAME),	/* KillModuleByName "name" module */
163 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "RestartModuleByName", F_RESTARTMODULEBYNAME),	/* RestartModuleByName "name" module */
164 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "KillAllModulesByName", F_KILLALLMODULESBYNAME),	/* KillAllModulesByName "name" module */
165 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "QuickRestart", F_QUICKRESTART),	/* QuickRestart "name" what */
166 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "Background", F_CHANGE_BACKGROUND),	/* Background "name" file_name */
167 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "BackgroundForeign", F_CHANGE_BACKGROUND_FOREIGN),	/* BackgroundForeign "name" file_name */
168 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "ChangeLook", F_CHANGE_LOOK),	/* ChangeLook "name" file_name */
169 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "ChangeFeel", F_CHANGE_FEEL),	/* ChangeFeel "name" file_name */
170 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "ChangeTheme", F_CHANGE_THEME),	/* ChangeTheme "name" file_name */
171 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "ChangeThemeFile", F_CHANGE_THEME_FILE),	/* "name" file_name */
172 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "ChangeColorscheme", F_CHANGE_COLORSCHEME),	/* ChangeColorscheme "name" file_name */
173 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallLook", F_INSTALL_LOOK),	/*  "name" file_name */
174 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallFeel", F_INSTALL_FEEL),	/*  "name" file_name */
175 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallBackground", F_INSTALL_BACKGROUND),	/* "name" file_name */
176 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallFont", F_INSTALL_FONT),	/* "name" file_name */
177 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallIcon", F_INSTALL_ICON),	/*  "name" file_name */
178 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallTile", F_INSTALL_TILE),	/*  "name" file_name */
179 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallThemeFile", F_INSTALL_THEME_FILE),	/*  "name" file_name */
180 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "InstallColorscheme", F_INSTALL_COLORSCHEME),	/*  "name" file_name */
181 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "SaveWorkspace", F_SAVE_WORKSPACE),	/* SaveWorkspace "name" file_name */
182 	FUNC_TERM ("SignalReloadGTKRCFile", F_SIGNAL_RELOAD_GTK_RCFILE),
183 	FUNC_TERM ("KIPCsendMessageAll", F_KIPC_SEND_MESSAGE_ALL),
184 	FUNC_TERM2 (TF_SYNTAX_TERMINATOR, "EndFunction", F_ENDFUNC),
185 	FUNC_TERM2 (TF_SYNTAX_TERMINATOR, "EndPopup", F_ENDPOPUP),
186 	FUNC_TERM ("TakeScreenShot", F_TAKE_SCREENSHOT),
187 
188 	FUNC_TERM2 (NEED_CMD, "Set", F_SET),	/* Set "name" <variable>=<value> */
189 
190 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "Test", F_Test),
191 	FUNC_TERM2 (NEED_NAME | NEED_CMD, "Remap", F_Remap),
192 
193 	/* this functions require window as aparameter */
194 	FUNC_TERM ("&nonsense&", F_WINDOW_FUNC_START),	/* not really a command */
195 	FUNC_TERM2 (USES_NUMVALS, "Move", F_MOVE),	/* Move     ["name"] [whereX whereY] */
196 	FUNC_TERM2 (USES_NUMVALS, "Resize", F_RESIZE),	/* Resize   ["name"] [toWidth toHeight] */
197 	FUNC_TERM ("Raise", F_RAISE),	/* Raise    ["name"] */
198 	FUNC_TERM ("Lower", F_LOWER),	/* Lower    ["name"] */
199 	FUNC_TERM ("RaiseLower", F_RAISELOWER),	/* RaiseLower ["name"] */
200 	FUNC_TERM ("PutOnTop", F_PUTONTOP),	/* PutOnTop  */
201 	FUNC_TERM ("PutOnBack", F_PUTONBACK),	/* PutOnBack */
202 	FUNC_TERM2 (USES_NUMVALS, "SetLayer", F_SETLAYER),	/* SetLayer    layer */
203 	FUNC_TERM2 (USES_NUMVALS, "ToggleLayer", F_TOGGLELAYER),	/* ToggleLayer layer1 layer2 */
204 	FUNC_TERM ("Shade", F_SHADE),	/* Shade    ["name"] */
205 	FUNC_TERM ("Delete", F_DELETE),	/* Delete   ["name"] */
206 	FUNC_TERM ("Destroy", F_DESTROY),	/* Destroy  ["name"] */
207 	FUNC_TERM ("Close", F_CLOSE),	/* Close    ["name"] */
208 	FUNC_TERM ("Iconify", F_ICONIFY),	/* Iconify  ["name"] value */
209 	FUNC_TERM2 (USES_NUMVALS, "Maximize", F_MAXIMIZE),	/* Maximize ["name"] [hori vert] */
210 	FUNC_TERM ("Fullscreen", F_FULLSCREEN),	/* Maximize ["name"] [hori vert] */
211 	FUNC_TERM ("Stick", F_STICK),	/* Stick    ["name"] */
212 	FUNC_TERM ("Focus", F_FOCUS),	/* Focus */
213 	FUNC_TERM2 (NEED_WINIFNAME, "ChangeWindowUp", F_CHANGEWINDOW_UP),	/* ChangeWindowUp   ["name" window_name ] */
214 	FUNC_TERM2 (NEED_WINIFNAME, "ChangeWindowDown", F_CHANGEWINDOW_DOWN),	/* ChangeWindowDown ["name" window_name ] */
215 	FUNC_TERM2 (NEED_WINIFNAME, "GoToBookmark", F_GOTO_BOOKMARK),	/* GoToBookmark ["name" window_bookmark ] */
216 	FUNC_TERM ("GetHelp", F_GETHELP),	/* */
217 	FUNC_TERM ("PasteSelection", F_PASTE_SELECTION),	/* */
218 	FUNC_TERM2 (USES_NUMVALS, "WindowsDesk", F_CHANGE_WINDOWS_DESK),	/* WindowDesk "name" new_desk */
219 	FUNC_TERM ("BookmarkWindow", F_BOOKMARK_WINDOW),	/* BookmarkWindow "name" new_bookmark */
220 	FUNC_TERM ("PinMenu", F_PIN_MENU),	/* PinMenu ["name"] */
221 	FUNC_TERM ("TakeWindowShot", F_TAKE_WINDOWSHOT),
222 	FUNC_TERM ("TakeFrameShot", F_TAKE_FRAMESHOT),
223 	FUNC_TERM ("SwallowWindow", F_SWALLOW_WINDOW),	/* SwallowWindow "name" module_name */
224 	/* end of window functions */
225 	/* these are commands  to be used only by modules */
226 	FUNC_TERM ("&nonsense&", F_MODULE_FUNC_START),	/* not really a command */
227 	FUNC_TERM ("Send_WindowList", F_SEND_WINDOW_LIST),	/* */
228 	FUNC_TERM ("SET_MASK", F_SET_MASK),	/* SET_MASK  mask lock_mask */
229 	FUNC_TERM2 (NEED_NAME, "SET_NAME", F_SET_NAME),	/* SET_NAME  name */
230 	FUNC_TERM ("UNLOCK", F_UNLOCK),	/* UNLOCK    1  */
231 	FUNC_TERM ("SET_FLAGS", F_SET_FLAGS),	/* SET_FLAGS flags */
232 	/* these are internal commands */
233 	FUNC_TERM ("&nonsense&", F_INTERNAL_FUNC_START),	/* not really a command */
234 	FUNC_TERM ("&raise_it&", F_RAISE_IT),	/* should not be used by user */
235 	/* wharf functions : */
236 	{TF_NO_MYNAME_PREPENDING, "Folder", 6, TT_FUNCTION, F_Folder, NULL},
237 	{TF_NO_MYNAME_PREPENDING | NEED_NAME | NEED_CMD | TF_NAMED, "Swallow", 7,
238 	 TT_FUNCTION, F_Swallow, NULL},
239 	{TF_NO_MYNAME_PREPENDING | NEED_NAME | NEED_CMD | TF_NAMED, "MaxSwallow",
240 	 10, TT_FUNCTION, F_MaxSwallow, NULL},
241 	{TF_NO_MYNAME_PREPENDING | NEED_NAME | NEED_CMD | TF_NAMED,
242 	 "SwallowModule", 13, TT_FUNCTION, F_SwallowModule,
243 	 NULL},
244 	{TF_NO_MYNAME_PREPENDING | NEED_NAME | NEED_CMD | TF_NAMED,
245 	 "MaxSwallowModule", 16, TT_FUNCTION, F_MaxSwallowModule,
246 	 NULL},
247 	{TF_NO_MYNAME_PREPENDING, "Size", 4, TT_FUNCTION, F_Size, NULL},
248 	{TF_NO_MYNAME_PREPENDING, "Transient", 9, TT_FUNCTION, F_Transient,
249 	 NULL},
250 
251 	{0, NULL, 0, 0, 0}
252 };
253 
254 struct SyntaxDef FuncSyntax = {
255 	'\0', '\n', FuncTerms,
256 	0, ' ', "", "\t",
257 	"AfterStep Function",
258 	"Functions",
259 	"built in AfterStep functions",
260 	NULL, 0
261 };
262 
263 SyntaxDef PopupFuncSyntax = {
264 	'\n', '\0', FuncTerms,
265 	0, ' ', "\t", "\t",
266 	"Popup/Complex function definition",
267 	"Popup",
268 	"",
269 	NULL, 0
270 };
271 
272 
273 
274 struct SyntaxDef *pFuncSyntax = &FuncSyntax;
275 struct SyntaxDef *pPopupFuncSyntax = &PopupFuncSyntax;
276 
func2fterm(FunctionCode func,int quiet)277 TermDef *func2fterm (FunctionCode func, int quiet)
278 {
279 	register int i;
280 
281 	/* in most cases that should work : */
282 	if (func < F_FUNCTIONS_NUM)
283 		if (FuncTerms[func].id == func)
284 			return &(FuncTerms[func]);
285 
286 	/* trying fallback if it did not : */
287 	for (i = 0; i < F_FUNCTIONS_NUM; i++)
288 		if (FuncTerms[i].id == func)
289 			return &(FuncTerms[i]);
290 
291 	/* something terribly wrong has happened : */
292 	return NULL;
293 }
294 
295 /************************************************************************************/
296 /* Command Line Processing/ App initialization here :                               */
297 /************************************************************************************/
SetMyClass(const char * app_class)298 void SetMyClass (const char *app_class)
299 {
300 	if (app_class != NULL) {
301 		strncpy (MyClass, (char *)app_class, MAX_MY_CLASS);
302 		MyClass[MAX_MY_CLASS] = '\0';
303 	}
304 }
305 
SetMyName(char * argv0)306 void SetMyName (char *argv0)
307 {
308 	char *temp = strrchr (argv0, '/');
309 
310 	/* Save our program name - for error messages */
311 	MyName = temp ? temp + 1 : argv0;
312 	set_application_name (argv0);
313 }
314 
315 /* If you change/add options please change InitMyApp below and option flags in aftersteplib.h */
316 
317 CommandLineOpts as_standard_cmdl_options[STANDARD_CMDL_OPTS_NUM] = {
318 #define  SHOW_VERSION   0
319 #define  SHOW_CONFIG    1
320 #define  SHOW_USAGE     2
321 /* 0*/ {"v", "version", "Display version information and stop", NULL,
322 				handler_show_info, NULL, SHOW_VERSION},
323 /* 1*/ {"c", "config", "Display Config information and stop", NULL,
324 				handler_show_info, NULL, SHOW_CONFIG},
325 /* 2*/ {"h", "help", "Display uasge information and stop", NULL,
326 				handler_show_info, NULL, SHOW_USAGE},
327 /* 3*/ {NULL, "debug", "Debugging: Run in Synchronous mode", NULL,
328 				handler_set_flag, &(as_app_args.flags),
329 				ASS_Debugging},
330 /* 4*/ {"s", "single", "Run on single screen only", NULL,
331 				handler_set_flag, &(as_app_args.flags), ASS_SingleScreen},
332 /* 5*/ {"r", "restart", "Run as if it was restarted",
333 				"same as regular startup, only \nruns RestartFunctioninstead of InitFunction",
334 				handler_set_flag, &(as_app_args.flags), ASS_Restarting},
335 #define OPTION_HAS_ARGS     6
336 /* 6*/ {"d", "display", "Specify what X display we should connect to",
337 				"Overrides $DISPLAY environment variable",
338 				handler_set_string, &(as_app_args.display_name), 0, CMO_HasArgs},
339 /* 7*/ {"f", "config-file", "Read all config from requested file",
340 				"Use it if you want to use .steprc\ninstead of standard config files",
341 				handler_set_string, &(as_app_args.override_config), 0,
342 				CMO_HasArgs},
343 /* 8*/ {"p", "user-dir", "Read all the config from requested dir",
344 				"Use it to override config location\nrequested in compile time",
345 				handler_set_string, &(as_app_args.override_home), 0, CMO_HasArgs},
346 /* 9*/ {"g", "global-dir", "Use requested dir as a shared config dir",
347 				"Use it to override shared config location\nrequested in compile time",
348 				handler_set_string, &(as_app_args.override_share), 0, CMO_HasArgs},
349 /*10*/ {"V", "verbosity-level",
350 				"Change verbosity of the AfterStep output",
351 				"0 - will disable any output;\n1 - will allow only error messages;\n5 - both errors and warnings(default)",
352 				handler_set_int, &(as_app_args.verbosity_level), 0, CMO_HasArgs},
353 /*11*/ {NULL, "window", "Internal Use: Window in which action occured",
354 				"interface part which has triggered our startup",
355 				handler_set_int, &(as_app_args.src_window), 0, CMO_HasArgs},
356 /*12*/ {NULL, "context", "Internal Use: Context in which action occured",
357 				"interface part which has triggered our startup",
358 				handler_set_int, &(as_app_args.src_context), 0, CMO_HasArgs},
359 /*13*/ {NULL, "look", "Read look config from requested file",
360 				"Use it if you want to use different look\ninstead of what was selected from the menu",
361 				handler_set_string, &(as_app_args.override_look), 0, CMO_HasArgs},
362 /*14*/ {NULL, "feel", "Read feel config from requested file",
363 				"Use it if you want to use different feel\ninstead of what was selected from the menu",
364 				handler_set_string, &(as_app_args.override_feel), 0, CMO_HasArgs},
365 /*15*/ {NULL, "theme", "Read theme config from requested file",
366 				"Use it if you want to use different theme\ninstead of what was selected from the menu",
367 				handler_set_string, &(as_app_args.override_feel), 0, CMO_HasArgs},
368 #ifdef DEBUG_TRACE_X
369 /*16*/ {NULL, "trace-func",
370 				"Debugging: Trace calls to a function with requested name", NULL,
371 				handler_set_string, &(as_app_args.trace_calls), 0, CMO_HasArgs},
372 #endif
373 /*17*/ {"l", "log", "Save all output into the file",
374 				"(instead of printing it to console)",
375 				handler_set_string, &(as_app_args.log_file), 0, CMO_HasArgs},
376 /*18*/ {"L", "locale", "Set language locale",
377 				"to be used while displaying text",
378 				handler_set_dup_string, &(as_app_args.locale), 0, CMO_HasArgs},
379 /*19*/ {NULL, "myname", "Overrides module name",
380 				"will be used while parsing config files\nand reporting to AfterStep",
381 				handler_set_string, &(MyName), 0, CMO_HasArgs},
382 /*20*/ {NULL, "geometry", "Overrides module's geometry", NULL,
383 				handler_set_geometry, &(as_app_args.geometry), 0, CMO_HasArgs},
384 /*21*/ {NULL, "gravity", "Overrides module's gravity", NULL,
385 				handler_set_gravity, &(as_app_args.gravity), 0, CMO_HasArgs},
386 	{NULL, NULL, NULL, NULL, NULL, NULL, 0}
387 };
388 
standard_version(void)389 void standard_version (void)
390 {
391 	show_debug (__FILE__, __FUNCTION__, __LINE__,
392 							"version = \"%s\", MyVersionFunc = %p", VERSION,
393 							MyVersionFunc);
394 
395 	if (MyVersionFunc)
396 		MyVersionFunc ();
397 	else
398 		printf ("%s version %s\n", MyClass, VERSION);
399 }
400 
401 void
print_command_line_opt(const char * prompt,CommandLineOpts * options,ASFlagType mask)402 print_command_line_opt (const char *prompt, CommandLineOpts * options,
403 												ASFlagType mask)
404 {
405 	register int i;
406 	ASFlagType bit = 0x01;
407 
408 	if (options == NULL)
409 		options = as_standard_cmdl_options;
410 	printf ("%s:\n", prompt);
411 
412 	for (i = 0; options[i].handler != NULL; i++) {
413 		if (!get_flags (bit, mask)) {
414 			if (options[i].short_opt)
415 				printf (OPTION_SHORT_FORMAT, options[i].short_opt);
416 			else
417 				printf (OPTION_NOSHORT_FORMAT);
418 
419 			if (!get_flags (options[i].flags, CMO_HasArgs))
420 				printf (OPTION_DESCR1_FORMAT_NOVAL, options[i].long_opt,
421 								options[i].descr1);
422 			else
423 				printf (OPTION_DESCR1_FORMAT_VAL, options[i].long_opt,
424 								options[i].descr1);
425 
426 			if (options[i].descr2) {
427 				register char *start = options[i].descr2;
428 				register char *end;
429 
430 				do {
431 					end = strchr (start, '\n');
432 					if (end == NULL)
433 						printf (OPTION_DESCR2_FORMAT, start);
434 					else {
435 						static char buffer[81];
436 						register int len = (end > start + 80) ? 80 : end - start;
437 
438 						strncpy (buffer, start, len);
439 						buffer[len] = '\0';
440 						printf (OPTION_DESCR2_FORMAT, buffer);
441 						start = end + 1;
442 					}
443 				}
444 				while (end != NULL);
445 			}
446 		}
447 		bit = bit << 1;
448 	}
449 }
450 
standard_usage()451 void standard_usage ()
452 {
453 	standard_version ();
454 	if (MyUsageFunc)
455 		MyUsageFunc ();
456 	else
457 		printf (OPTION_USAGE_FORMAT "\n", MyName);
458 	print_command_line_opt ("standard_options are :",
459 													as_standard_cmdl_options, as_app_args.mask);
460 }
461 
handler_show_info(char * argv,void * trg,long param)462 void handler_show_info (char *argv, void *trg, long param)
463 {
464 	switch (param) {
465 	case SHOW_VERSION:
466 		standard_version ();
467 		break;
468 	case SHOW_CONFIG:
469 		standard_version ();
470 		printf ("BinDir            %s\n", AFTER_BIN_DIR);
471 		printf ("ManDir            %s\n", AFTER_MAN_DIR);
472 		printf ("DocDir            %s\n", AFTER_DOC_DIR);
473 		printf ("ShareDir          %s\n", AFTER_SHAREDIR);
474 		printf ("AfterDir          %s\n", AFTER_DIR);
475 		break;
476 	case SHOW_USAGE:
477 		standard_usage ();
478 		break;
479 	}
480 	exit (0);
481 }
482 
handler_set_flag(char * argv,void * trg,long param)483 void handler_set_flag (char *argv, void *trg, long param)
484 {
485 	register ASFlagType *f = trg;
486 
487 	set_flags (*f, param);
488 }
489 
handler_set_string(char * argv,void * trg,long param)490 void handler_set_string (char *argv, void *trg, long param)
491 {
492 	register char **s = trg;
493 
494 	if (argv)
495 		*s = argv;
496 }
497 
handler_set_dup_string(char * argv,void * trg,long param)498 void handler_set_dup_string (char *argv, void *trg, long param)
499 {
500 	register char **s = trg;
501 
502 	if (argv) {
503 		if (*s)
504 			free (*s);
505 		*s = mystrdup (argv);
506 	}
507 }
508 
handler_set_int(char * argv,void * trg,long param)509 void handler_set_int (char *argv, void *trg, long param)
510 {
511 	register int *i = trg;
512 
513 	if (argv)
514 		*i = atoi (argv);
515 }
516 
handler_set_geometry(char * argv,void * trg,long param)517 void handler_set_geometry (char *argv, void *trg, long param)
518 {
519 	register ASGeometry *geom = trg;
520 
521 	if (argv) {
522 		memset (geom, 0x00, sizeof (ASGeometry));
523 		parse_geometry (argv, &(geom->x), &(geom->y), &(geom->width),
524 										&(geom->height), &(geom->flags));
525 	}
526 }
527 
handler_set_gravity(char * argv,void * trg,long param)528 void handler_set_gravity (char *argv, void *trg, long param)
529 {
530 	register int *i = trg;
531 
532 	*i = ForgetGravity;
533 	if (argv) {
534 
535 		if (mystrncasecmp (argv, "NorthWest", 9) == 0)
536 			*i = NorthWestGravity;
537 		else if (mystrncasecmp (argv, "SouthWest", 9) == 0)
538 			*i = SouthWestGravity;
539 		else if (mystrncasecmp (argv, "NorthEasth", 10) == 0)
540 			*i = NorthEastGravity;
541 		else if (mystrncasecmp (argv, "SouthEast", 9) == 0)
542 			*i = SouthEastGravity;
543 		else if (mystrncasecmp (argv, "Center", 6) == 0)
544 			*i = CenterGravity;
545 		else if (mystrncasecmp (argv, "Static", 6) == 0)
546 			*i = StaticGravity;
547 		else
548 			show_warning
549 					("unknown gravity type \"%s\". Use one of: NorthWest, SouthWest, NorthEast, SouthEast, Center, Static",
550 					 argv);
551 	}
552 }
553 
554 
match_command_line_opt(char * argvi,CommandLineOpts * options)555 int match_command_line_opt (char *argvi, CommandLineOpts * options)
556 {
557 	register char *ptr = argvi;
558 	register int opt;
559 
560 	if (ptr == NULL)
561 		return -1;
562 	show_debug (__FILE__, __FUNCTION__, __LINE__, "ptr = \"%s\"", ptr);
563 	if (*ptr == '-') {
564 		++ptr;
565 		if (*ptr == '-') {
566 			++ptr;
567 			show_debug (__FILE__, __FUNCTION__, __LINE__, "ptr = \"%s\"", ptr);
568 			for (opt = 0; options[opt].handler; ++opt)
569 				if (strcmp (options[opt].long_opt, ptr) == 0)
570 					break;
571 		} else {
572 			show_debug (__FILE__, __FUNCTION__, __LINE__, "ptr = \"%s\"", ptr);
573 			for (opt = 0; options[opt].handler; ++opt)
574 				if (options[opt].short_opt)
575 					if (strcmp (options[opt].short_opt, ptr) == 0)
576 						break;
577 		}
578 	} else
579 		opt = -1;
580 	if (options[opt].handler == NULL)
581 		opt = -1;
582 	return opt;
583 }
584 
585 static DeadPipe_handler _as_dead_pipe_handler = NULL;
586 
set_DeadPipe_handler(DeadPipe_handler new_handler)587 DeadPipe_handler set_DeadPipe_handler (DeadPipe_handler new_handler)
588 {
589 	DeadPipe_handler old = _as_dead_pipe_handler;
590 
591 	_as_dead_pipe_handler = new_handler;
592 	return old;
593 }
594 
ASDeadPipe(int nonsense)595 void ASDeadPipe (int nonsense)
596 {
597 	if (_as_dead_pipe_handler)
598 		_as_dead_pipe_handler (nonsense);
599 	else
600 		exit (0);
601 }
602 
603 static char **AS_environ = NULL;
604 
override_environ(char ** envp)605 void override_environ (char **envp)
606 {
607 	AS_environ = envp;
608 }
609 
610 void
InitMyApp(const char * app_class,int argc,char ** argv,void (* version_func)(void),void (* custom_usage_func)(void),ASFlagType opt_mask)611 InitMyApp (const char *app_class, int argc, char **argv,
612 					 void (*version_func) (void), void (*custom_usage_func) (void),
613 					 ASFlagType opt_mask)
614 {
615 	/* first of all let's set us some nice signal handlers */
616 #ifdef HAVE_SIGSEGV_HANDLING
617 	set_signal_handler (SIGSEGV);
618 #endif
619 
620 	set_signal_handler (SIGUSR2);
621 	signal (SIGPIPE, ASDeadPipe);	/* don't forget DeadPipe should be provided by the app */
622 
623 	SetMyClass (app_class);
624 	MyVersionFunc = version_func;
625 	MyUsageFunc = custom_usage_func;
626 
627 	memset (&as_app_args, 0x00, sizeof (ASProgArgs));
628 	as_app_args.locale = mystrdup (AFTER_LOCALE);
629 	if (as_app_args.locale[0] == '\0') {
630 		free (as_app_args.locale);
631 		as_app_args.locale = mystrdup (getenv ("LANG"));
632 	}
633 
634 	as_app_args.mask = opt_mask;
635 	as_app_args.gravity = ForgetGravity;
636 #ifndef NO_DEBUG_OUTPUT
637 	as_app_args.verbosity_level = OUTPUT_VERBOSE_THRESHOLD;
638 #else
639 	as_app_args.verbosity_level = OUTPUT_DEFAULT_THRESHOLD;
640 #endif
641 
642 /* Uncomment this to enable cmd line args tracing/debugging :
643  * set_output_threshold(20); */
644 
645 	ASDefaultScr = safecalloc (1, sizeof (ScreenInfo));
646 	init_ScreenInfo (ASDefaultScr);
647 	show_debug (__FILE__, __FUNCTION__, __LINE__, "argc = %d", argc);
648 
649 	if (argc > 0 && argv) {
650 		int i;
651 
652 		as_app_args.saved_argc = argc;
653 		as_app_args.saved_argv = safecalloc (argc, sizeof (char *));
654 		for (i = 0; i < argc; ++i)
655 			as_app_args.saved_argv[i] = mystrdup (argv[i]);
656 
657 		SetMyName (argv[0]);
658 
659 		for (i = 1; i < argc; i++) {
660 			register int opt;
661 
662 			show_debug (__FILE__, __FUNCTION__, __LINE__,
663 									"i = %d, argv[i] = 0x%p", i, argv[i]);
664 			if ((opt =
665 					 match_command_line_opt (&(argv[i][0]),
666 																	 as_standard_cmdl_options)) < 0)
667 				continue;
668 			if (get_flags ((0x01 << opt), as_app_args.mask))
669 				continue;
670 			if (get_flags (as_standard_cmdl_options[opt].flags, CMO_HasArgs)) {
671 				argv[i] = NULL;
672 				if (++i >= argc)
673 					continue;
674 				else
675 					as_standard_cmdl_options[opt].handler (argv[i],
676 																								 as_standard_cmdl_options
677 																								 [opt].trg,
678 																								 as_standard_cmdl_options
679 																								 [opt].param);
680 			} else
681 				as_standard_cmdl_options[opt].handler (NULL,
682 																							 as_standard_cmdl_options
683 																							 [opt].trg,
684 																							 as_standard_cmdl_options
685 																							 [opt].param);
686 			argv[i] = NULL;
687 		}
688 	}
689 
690 	set_output_threshold (as_app_args.verbosity_level);
691 	if (as_app_args.log_file)
692 		if (freopen (as_app_args.log_file,
693 								 /*get_flags( as_app_args.flags, ASS_Restarting)? */
694 								 "a" /*:"w" */ , stderr)
695 				== NULL)
696 			show_system_error ("failed to redirect output into file \"%s\"",
697 												 as_app_args.log_file);
698 
699 
700 	fd_width = get_fd_width ();
701 
702 	if (FuncSyntax.term_hash == NULL)
703 		PrepareSyntax (&FuncSyntax);
704 	if (as_app_args.locale == NULL)
705 		as_app_args.locale = mystrdup ("");
706 	if (as_app_args.locale && strlen (as_app_args.locale) > 0) {
707 		as_set_charset (parse_charset_name (as_app_args.locale));
708 #ifdef I18N
709 		if (strlen (as_app_args.locale) > 0)
710 			if (setlocale (LC_CTYPE, as_app_args.locale) == NULL) {
711 				show_error ("unable to set locale");
712 			}
713 #endif
714 	} else {
715 #ifdef I18N
716 		show_warning
717 				("LANG environment variable is not set - use -L \"locale\" command line option to define locale");
718 #endif
719 	}
720 
721 #ifdef DEBUG_TRACE_X
722 	trace_enable_function (as_app_args.trace_calls);
723 #endif
724 
725 	asxml_var_insert (ASXMLVAR_IconButtonWidth, 64);
726 	asxml_var_insert (ASXMLVAR_IconButtonHeight, 64);
727 	asxml_var_insert (ASXMLVAR_IconWidth, 48);
728 	asxml_var_insert (ASXMLVAR_IconHeight, 48);
729 	asxml_var_insert (ASXMLVAR_MinipixmapWidth, 24);
730 	asxml_var_insert (ASXMLVAR_MinipixmapHeight, 24);
731 	asxml_var_insert (ASXMLVAR_TitleFontSize, 14);
732 	asxml_var_insert (ASXMLVAR_MenuFontSize, 16);
733 	asxml_var_insert (ASXMLVAR_MenuShowMinipixmaps, 1);
734 	asxml_var_insert (ASXMLVAR_MenuShowUnavailable, 1);
735 
736 }
737 
free_func_hash()738 void free_func_hash ()
739 {
740 	if (FuncSyntax.term_hash) {
741 		FreeSyntaxHash (&FuncSyntax);
742 	}
743 }
744 
745 /*********** end command line parsing **************************/
746 static char *_as_known_terms[] = {
747 	"x-terminal-emulator",
748 	"urxvt",
749 	"aterm",
750 	"rxvt  -tr -fg yellow -bg black",
751 	"Eterm -tr -tint blue -fg yellow -bg black",
752 	"xterm -fg yellow -bg blue",
753 	NULL
754 };
755 
756 static char *_as_known_browsers[] = {
757 	"$BROWSER",
758 	"sensible-browser",
759 	"x-www-browser",							/* don't like default debian selection of konqueror */
760 	"firefox",
761 	"mozilla-firefox",
762 	"mozilla",
763 	"opera",
764 	NULL
765 };
766 
767 static char *_as_known_editors[] = {
768 	"editor",
769 	"$EDITOR",
770 	"nedit",
771 	"xemacs",
772 	"gedit",
773 	"kedit",
774 	"kate",
775 	NULL
776 };
777 
778 static char **_as_known_tools[ASTool_Count] = {
779 	_as_known_terms,
780 	_as_known_browsers,
781 	_as_known_editors
782 };
783 
784 static char *_as_tools_name[ASTool_Count] = {
785 	"Terminal",
786 	"Browser",
787 	"Editor"
788 };
789 
790 
as_get_default_tool(ASToolType type)791 char *as_get_default_tool (ASToolType type)
792 {
793 	int i;
794 
795 	for (i = 0; _as_known_tools[type][i]; ++i) {
796 		char *tmp = _as_known_tools[type][i];
797 		char *fullname = NULL;
798 		int res;
799 
800 		if (tmp[0] == '$')
801 			tmp = copy_replace_envvar (tmp);
802 		res = get_executable_in_path (tmp, &fullname);
803 		if (tmp != _as_known_tools[type][i])
804 			free (tmp);
805 		if (res > 0)
806 			return fullname;
807 	}
808 	return NULL;
809 }
810 
811 void
set_environment_tool_from_list(ASEnvironment * e,ASToolType type,char ** list,int list_len)812 set_environment_tool_from_list (ASEnvironment * e, ASToolType type,
813 																char **list, int list_len)
814 {
815 	int i;
816 
817 	destroy_string (&(e->tool_command[type]));
818 	for (i = 0; i < list_len; ++i)
819 		if (list[i]) {
820 			char *tmp = list[i];
821 			char *fullname = NULL;
822 
823 			if (tmp[0] == '$')
824 				tmp = copy_replace_envvar (tmp);
825 			if (get_executable_in_path (tmp, &fullname)) {
826 				e->tool_command[type] = fullname;
827 				break;
828 			} else
829 				show_warning ("%s command %s is not in the path",
830 											_as_tools_name[type], tmp);
831 			if (tmp != list[i])
832 				free (tmp);
833 		}
834 	if (e->tool_command[type] == NULL)
835 		e->tool_command[type] = as_get_default_tool (type);
836 	show_progress ("%s is set to: \"%s\"", _as_tools_name[type],
837 								 e->tool_command[type] ? e->tool_command[type] : "none");
838 }
839 
make_themed_icon_category_path(const char * category,int desired_size_idx,Bool fallback)840 static char *make_themed_icon_category_path (const char *category,
841 																						 int desired_size_idx,
842 																						 Bool fallback)
843 {
844 	char *tmp, *tmp2, *theme_path;
845 	static char *standard_sizes[] =
846 			{ "16x16", "32x32", "48x48", "64x64", "128x128", NULL };
847 
848 	if (!fallback && Environment->IconTheme == NULL)
849 		return NULL;
850 	if (fallback && Environment->IconThemeFallback == NULL)
851 		return NULL;
852 
853 	tmp =
854 			make_file_name (fallback ? Environment->
855 											IconThemeFallback : Environment->IconTheme,
856 											standard_sizes[desired_size_idx]);
857 	tmp2 = make_file_name (Environment->IconThemePath, tmp);
858 	free (tmp);
859 	theme_path = make_file_name (tmp2, category);
860 	free (tmp2);
861 
862 	return theme_path;
863 }
864 
is_themable_icon(const char * name)865 Bool is_themable_icon (const char *name)
866 {
867 	return (Environment && Environment->IconTheme
868 					&& Environment->IconThemePath && strchr (name, '/') == NULL);
869 }
870 
load_environment_icon(const char * category,const char * name,int desired_size)871 ASImage *load_environment_icon (const char *category, const char *name,
872 																int desired_size)
873 {
874 	ASImage *icon = NULL;
875 	char *png_name = NULL;
876 	char *svg_name = NULL;
877 	Bool add_to_man = False;
878 	int len;
879 	int desired_size_idx;
880 
881 	if (name == NULL || ASDefaultScr == NULL)
882 		return NULL;
883 
884 	desired_size_idx = (desired_size + 15) / 16 - 1;
885 	if (desired_size_idx > 4)
886 		desired_size_idx = 4;
887 	else if (desired_size_idx < 0)
888 		desired_size_idx = 0;
889 
890 	show_debug (__FILE__, __FUNCTION__, __LINE__, "IconTheme = %s",
891 							Environment->IconTheme);
892 
893 	len = strlen (name);
894 	if (len < 4 || name[len - 4] != '.') {
895 		png_name = add_file_extension (name, "png");
896 		svg_name = add_file_extension (name, "svg");
897 	}
898 	/* we maybe already loaded so try with just the name : */
899 	icon = fetch_asimage (ASDefaultScr->image_manager, name);
900 
901 	/* nope we are not, so try loading as themed icon first: */
902 	if (icon == NULL && is_themable_icon (name) && category) {
903 		int fallback;
904 		for (fallback = 0; fallback <= 1; fallback++) {
905 			int try, try_size_idx = desired_size_idx;
906 			for (try = 0; icon == NULL && try < 3; ++try) {
907 				char *theme_path =
908 						make_themed_icon_category_path (category, try_size_idx,
909 																						fallback);
910 				if (theme_path == NULL)
911 					break;
912 
913 				if (icon == NULL && png_name) {
914 					char *themed_name = make_file_name (theme_path, png_name);
915 					icon =
916 							get_asimage_quiet (ASDefaultScr->image_manager, themed_name,
917 																 ASFLAGS_EVERYTHING, 100);
918 					free (themed_name);
919 				}
920 				if (icon == NULL && svg_name) {
921 					char *themed_name = make_file_name (theme_path, svg_name);
922 					icon =
923 							get_asimage_quiet (ASDefaultScr->image_manager, themed_name,
924 																 ASFLAGS_EVERYTHING, 100);
925 					free (themed_name);
926 				}
927 				if (icon == NULL) {
928 					char *themed_name = make_file_name (theme_path, name);
929 					icon =
930 							get_asimage_quiet (ASDefaultScr->image_manager, themed_name,
931 																 ASFLAGS_EVERYTHING, 100);
932 					free (themed_name);
933 				}
934 				free (theme_path);
935 				switch (try) {
936 				case 0:
937 					try_size_idx =
938 							desired_size_idx <
939 							4 ? desired_size_idx + 1 : desired_size_idx - 1;
940 					break;
941 				case 1:
942 					try_size_idx = desired_size_idx == 0
943 							|| desired_size_idx == 4 ? 2 : desired_size_idx - 1;
944 					break;
945 				default:
946 					break;
947 				}
948 			}
949 		}
950 		add_to_man = True;
951 	}
952 
953 	/* finally, try loading straight (for native AS icons primarily): */
954 	if (icon == NULL) {
955 		icon =
956 				get_asimage_quiet (ASDefaultScr->image_manager, name,
957 													 ASFLAGS_EVERYTHING, 100);
958 		if (icon == NULL) {
959 			add_to_man = True;
960 			if (png_name)
961 				icon =
962 						get_asimage_quiet (ASDefaultScr->image_manager, png_name,
963 															 ASFLAGS_EVERYTHING, 100);
964 			if (icon == NULL && svg_name)
965 				icon =
966 						get_asimage_quiet (ASDefaultScr->image_manager, svg_name,
967 															 ASFLAGS_EVERYTHING, 100);
968 		}
969 	}
970 
971 	if (icon && add_to_man && icon->ref_count == 1) {
972 		forget_asimage (icon);
973 		if (icon->imageman == NULL)
974 			store_asimage (ASDefaultScr->image_manager, icon, name);
975 	}
976 	if (png_name)
977 		free (png_name);
978 	if (svg_name)
979 		free (svg_name);
980 	return icon;
981 }
982 
load_environment_icon_any(const char * filename,int desired_size)983 ASImage *load_environment_icon_any (const char *filename, int desired_size)
984 {
985 	ASImage *icon = NULL;
986 	if (filename) {
987 		Bool possibly_themed = is_themable_icon (filename);
988 		icon = load_environment_icon ("apps", filename, desired_size);
989 		if (!icon && possibly_themed)
990 			icon = load_environment_icon ("actions", filename, desired_size);
991 		if (!icon && possibly_themed)
992 			icon = load_environment_icon ("places", filename, desired_size);
993 		if (!icon && possibly_themed)
994 			icon = load_environment_icon ("categories", filename, desired_size);
995 		if (!icon && possibly_themed)
996 			icon = load_environment_icon ("devices", filename, desired_size);
997 	}
998 	return icon;
999 }
1000 
make_default_environment()1001 ASEnvironment *make_default_environment ()
1002 {
1003 	int i;
1004 	ASEnvironment *e = safecalloc (1, sizeof (ASEnvironment));
1005 	static const char *default_pixmap_path_format =
1006 			"%s/desktop/icons/:"
1007 			"%s/desktop/icons/:"
1008 			"%s/desktop/:"
1009 			"%s/desktop/:" "%s/desktop/buttons/:" "%s/desktop/buttons/:"
1010 			"%s/backgrounds/:" "%s/backgrounds/:" "%s";
1011 
1012 	static const char *default_font_path_format =
1013 			"%s/desktop/fonts/:" "%s/desktop/fonts/:"
1014 			"/usr/share/fonts/default/TrueType/:" "%s";
1015 
1016 	static const char *default_cursor_path_format =
1017 			"%s/desktop/cursors:" "%s/desktop/cursors";
1018 
1019 	e->desk_scale = 24;
1020 	e->desk_pages_h = 2;
1021 	e->desk_pages_v = 2;
1022 	e->module_path = mystrdup (AFTER_BIN_DIR);
1023 	e->icon_path = mystrdup (DEFAULT_ICON_DIR);
1024 	e->pixmap_path =
1025 			safemalloc (strlen ((char *)default_pixmap_path_format) +
1026 									strlen (AFTER_DIR) * 4 + strlen (AFTER_SHAREDIR) * 4 +
1027 									strlen (DEFAULT_PIXMAP_DIR) + 1);
1028 	sprintf (e->pixmap_path, default_pixmap_path_format, AFTER_DIR,
1029 					 AFTER_SHAREDIR, AFTER_DIR, AFTER_SHAREDIR, AFTER_DIR,
1030 					 AFTER_SHAREDIR, AFTER_DIR, AFTER_SHAREDIR, DEFAULT_PIXMAP_DIR);
1031 
1032 	e->font_path = safemalloc (strlen ((char *)default_font_path_format) +
1033 														 strlen (AFTER_DIR) + strlen (AFTER_SHAREDIR) +
1034 														 strlen (DEFAULT_TTF_DIR) + 1);
1035 	sprintf (e->font_path, default_font_path_format, AFTER_DIR,
1036 					 AFTER_SHAREDIR, DEFAULT_TTF_DIR);
1037 
1038 	e->cursor_path =
1039 			safemalloc (strlen ((char *)default_cursor_path_format) +
1040 									strlen (AFTER_DIR) + strlen (AFTER_SHAREDIR) + 1);
1041 	sprintf (e->cursor_path, default_cursor_path_format, AFTER_DIR,
1042 					 AFTER_SHAREDIR);
1043 
1044 	for (i = 0; i < ASTool_Count; ++i)
1045 		e->tool_command[i] = as_get_default_tool (i);
1046 
1047 	/* by default - don't do overwrite gtkrc files so to not aggrave people */
1048 	e->gtkrc_path = NULL;					/* make_session_rc_file(Session, GTKRC_FILE); */
1049 	e->gtkrc20_path = NULL;				/* make_session_rc_file(Session, GTKRC20_FILE) ; */
1050 	e->IconTheme = mystrdup ("oxygen");
1051 	e->IconThemePath = mystrdup ("/usr/chare/icons");
1052 	e->IconThemeFallback = mystrdup ("hicolor");
1053 	return e;
1054 }
1055 
destroy_asenvironment(ASEnvironment ** penv)1056 void destroy_asenvironment (ASEnvironment ** penv)
1057 {
1058 	if (penv) {
1059 		ASEnvironment *e = *penv;
1060 
1061 		if (e) {
1062 			int i;
1063 
1064 			if (e->module_path)
1065 				free (e->module_path);
1066 			if (e->sound_path)
1067 				free (e->sound_path);
1068 			if (e->icon_path)
1069 				free (e->icon_path);
1070 			if (e->pixmap_path)
1071 				free (e->pixmap_path);
1072 			if (e->font_path)
1073 				free (e->font_path);
1074 			if (e->cursor_path)
1075 				free (e->cursor_path);
1076 			for (i = 0; i < ASTool_Count; ++i)
1077 				destroy_string (&(e->tool_command[i]));
1078 
1079 			destroy_string (&(e->gtkrc_path));
1080 			destroy_string (&(e->gtkrc20_path));
1081 			destroy_string (&(e->IconTheme));
1082 			destroy_string (&(e->IconThemePath));
1083 			destroy_string (&(e->IconThemeFallback));
1084 
1085 			free (e);
1086 			*penv = NULL;
1087 		}
1088 	}
1089 }
1090 
1091 /*
1092  * Initialize database variables
1093  */
1094 
destroy_asdatabase()1095 void destroy_asdatabase ()
1096 {
1097 	if (Database)
1098 		destroy_asdb (&Database);
1099 	/* XResources : */
1100 	destroy_user_database ();
1101 }
1102 
name2desktop_category_tree(const char * name,int * tree_name_len)1103 static ASCategoryTree *name2desktop_category_tree (const char *name,
1104 																									 int *tree_name_len)
1105 {
1106 	ASCategoryTree *ct = CombinedCategories;
1107 	int offset = 0;
1108 
1109 /*	fprintf( stderr, __FUNCTION__ ": checking \"%s\" (AfterSTep categories = %p)\n", name, AfterStepCategories );*/
1110 
1111 	if (!mystrncasecmp (name, "AfterStep:", 10)) {
1112 		ct = AfterStepCategories;
1113 		offset = 10;
1114 	} else if (!mystrncasecmp (name, "KDE:", 4)) {
1115 		ct = KDECategories;
1116 		offset = 4;
1117 	} else if (!mystrncasecmp (name, "GNOME:", 6)) {
1118 		ct = GNOMECategories;
1119 		offset = 6;
1120 	} else if (!mystrncasecmp (name, "OTHER:", 7)) {
1121 		ct = OtherCategories;
1122 		offset = 7;
1123 	} else if (!mystrncasecmp (name, "COMBINED:", 9)) {
1124 		ct = CombinedCategories;
1125 		offset = 9;
1126 	}
1127 	if (tree_name_len)
1128 		*tree_name_len = offset;
1129 	return ct;
1130 }
1131 
name2desktop_category(const char * name,ASCategoryTree ** tree_return)1132 ASDesktopCategory *name2desktop_category (const char *name,
1133 																					ASCategoryTree ** tree_return)
1134 {
1135 	int offset = 0;
1136 	ASCategoryTree *ct = name2desktop_category_tree (name, &offset);
1137 
1138 	if (tree_return)
1139 		*tree_return = ct;
1140 
1141 	return fetch_desktop_category (ct, name + offset);
1142 }
1143 
name2desktop_entry(const char * name,ASCategoryTree ** tree_return)1144 ASDesktopEntry *name2desktop_entry (const char *name,
1145 																		ASCategoryTree ** tree_return)
1146 {
1147 	int offset = 0;
1148 	ASCategoryTree *ct = name2desktop_category_tree (name, &offset);
1149 
1150 	if (tree_return)
1151 		*tree_return = ct;
1152 
1153 	return fetch_desktop_entry (ct, name + offset);
1154 }
1155 
InitSession()1156 void InitSession ()
1157 {
1158 	/* initializing our dirs names */
1159 	if (Session == NULL) {
1160 		Session =
1161 				GetNCASSession (ASDefaultScr, as_app_args.override_home,
1162 												as_app_args.override_share);
1163 		if (as_app_args.override_config)
1164 			set_session_override (Session, as_app_args.override_config, 0);
1165 		if (as_app_args.override_look)
1166 			set_session_override (Session, as_app_args.override_look,
1167 														F_CHANGE_LOOK);
1168 		if (as_app_args.override_feel)
1169 			set_session_override (Session, as_app_args.override_feel,
1170 														F_CHANGE_FEEL);
1171 	}
1172 }
1173 
free_as_app_args()1174 void free_as_app_args ()
1175 {
1176 	int i;
1177 
1178 	for (i = 0; i < as_app_args.saved_argc; ++i)
1179 		if (as_app_args.saved_argv[i])
1180 			free (as_app_args.saved_argv[i]);
1181 	free (as_app_args.saved_argv);
1182 	as_app_args.saved_argv = NULL;
1183 
1184 	destroy_string (&(as_app_args.locale));
1185 
1186 }
1187 
FreeMyAppResources()1188 void FreeMyAppResources ()
1189 {
1190 	cleanup_default_balloons ();
1191 	destroy_asdatabase ();
1192 	mystyle_destroy_all ();
1193 	mylook_init (&(ASDefaultScr->Look), True, ASFLAGS_EVERYTHING);
1194 	destroy_image_manager (ASDefaultScr->image_manager, False);
1195 	destroy_font_manager (ASDefaultScr->font_manager, False);
1196 	clientprops_cleanup ();
1197 	destroy_wmprops (ASDefaultScr->wmprops, False);
1198 	wmprops_cleanup ();
1199 	free_func_hash ();
1200 	flush_keyword_ids ();
1201 	purge_asimage_registry ();
1202 	asxml_var_cleanup ();
1203 	custom_color_cleanup ();
1204 	build_xpm_colormap (NULL);
1205 	destroy_screen_gcs (ASDefaultScr);
1206 	if (ASDefaultScr->RootImage) {
1207 		safe_asimage_destroy (ASDefaultScr->RootImage);
1208 		ASDefaultScr->RootImage = NULL;
1209 	}
1210 	destroy_asvisual (ASDefaultScr->asv, False);
1211 	free_as_app_args ();
1212 	destroy_assession (Session);
1213 	Session = NULL;
1214 	destroy_asenvironment (&Environment);
1215 	is_executable_in_path (NULL);
1216 #ifdef XSHMIMAGE
1217 	flush_shm_cache ();
1218 #endif
1219 	free (ASDefaultScr);
1220 	flush_default_asstorage ();
1221 	flush_asbidirlist_memory_pool ();
1222 	flush_ashash_memory_pool ();
1223 
1224 }
1225 
1226 
1227 /************ child process spawning ***************************/
1228 /***********************************************************************
1229  *  Procedure:
1230  *  general purpose child launcher - spawn child.
1231  *  Pass along all the cmd line args if needed.
1232  *  returns PID of the spawned process
1233  ************************************************************************/
1234 static int as_singletons[MAX_SINGLETONS_NUM];
1235 static Bool as_init_singletons = True;
1236 
as_sigchild_handler(int signum)1237 void as_sigchild_handler (int signum)
1238 {
1239 	int pid;
1240 	int status;
1241 
1242 	signal (SIGCHLD, as_sigchild_handler);
1243 	DEBUG_OUT ("Entering SigChild_handler(%lu)", time (NULL));
1244 	if (as_init_singletons)
1245 		return;
1246 	while ((pid = WAIT_CHILDREN (&status)) > 0) {
1247 		register int i;
1248 
1249 		LOCAL_DEBUG_OUT ("pid = %d", pid);
1250 		for (i = 0; i < MAX_SINGLETONS_NUM; i++)
1251 			if (pid == as_singletons[i]) {
1252 				as_singletons[i] = 0;
1253 				break;
1254 			}
1255 	}
1256 	DEBUG_OUT ("Exiting SigChild_handler(%lu)", time (NULL));
1257 }
1258 
1259 /*
1260  * This should return 0 if process of running external app to draw background completed or killed.
1261  * otherwise it returns > 0
1262  */
check_singleton_child(int singleton_id,Bool kill_it_to_death)1263 int check_singleton_child (int singleton_id, Bool kill_it_to_death)
1264 {
1265 	int i;
1266 	int pid, status;
1267 
1268 	if (as_init_singletons || singleton_id < 0)
1269 		return -1;
1270 
1271 	if (singleton_id >= MAX_SINGLETONS_NUM)
1272 		singleton_id = MAX_SINGLETONS_NUM - 1;
1273 
1274 	DEBUG_OUT ("CheckingForDrawChild(%lu)....", time (NULL));
1275 	if ((pid = as_singletons[singleton_id]) > 0) {
1276 		DEBUG_OUT ("checking on singleton child #%d started with PID (%d)",
1277 							 singleton_id, pid);
1278 		if (kill_it_to_death) {
1279 			kill (pid, SIGTERM);
1280 			for (i = 0; i < 100; i++) {	/* give it 10 sec to terminate */
1281 				sleep_a_millisec (100);
1282 				if (WAIT_CHILDREN (&status) == pid
1283 						|| as_singletons[singleton_id] <= 0)
1284 					break;
1285 			}
1286 			if (i >= 100)
1287 				kill (pid, SIGKILL);		/* no more mercy */
1288 			as_singletons[singleton_id] = 0;
1289 		}
1290 	} else if (as_singletons[singleton_id] < 0)
1291 		as_singletons[singleton_id] = 0;
1292 
1293 	DEBUG_OUT ("Done(%lu). Child PID on exit = %d.", time (NULL),
1294 						 as_singletons[singleton_id]);
1295 	return as_singletons[singleton_id];
1296 }
1297 
1298 int
spawn_child(const char * cmd,int singleton_id,int screen,const char * orig_display,Window w,int context,Bool do_fork,Bool pass_args,...)1299 spawn_child (const char *cmd, int singleton_id, int screen,
1300 						 const char *orig_display, Window w, int context, Bool do_fork,
1301 						 Bool pass_args, ...)
1302 {
1303 	int pid = 0;
1304 
1305 	if (cmd == NULL)
1306 		return 0;
1307 	if (as_init_singletons) {
1308 		register int i;
1309 
1310 		for (i = 0; i < MAX_SINGLETONS_NUM; i++)
1311 			as_singletons[i] = 0;
1312 		signal (SIGCHLD, as_sigchild_handler);
1313 		as_init_singletons = False;
1314 	}
1315 
1316 	if (singleton_id >= 0) {
1317 		if (singleton_id >= MAX_SINGLETONS_NUM)
1318 			singleton_id = MAX_SINGLETONS_NUM - 1;
1319 		if (as_singletons[singleton_id] > 0)
1320 			check_singleton_child (singleton_id, True);
1321 	}
1322 
1323 	if (do_fork)
1324 		pid = fork ();
1325 
1326 	if (pid != 0) {
1327 		/* there is a possibility of the race condition here
1328 		 * but it really is not worse the trouble to try and avoid it.
1329 		 */
1330 		if (singleton_id >= 0)
1331 			as_singletons[singleton_id] = pid;
1332 		return pid;
1333 	} else {											/* we get here only in child process. We now need to spawn new proggy here: */
1334 		int len;
1335 		char *display = mystrdup (XDisplayString (dpy));
1336 		char **envp;
1337 		register char *ptr;
1338 
1339 		char *cmdl;
1340 		char *arg, *screen_str = NULL, *w_str = NULL, *context_str = NULL;
1341 		int env_s = 0;
1342 		char **envvars = AS_environ;
1343 		int font_path_slot = -1, image_path_slot = -1;
1344 
1345 		va_list ap;
1346 
1347 		LOCAL_DEBUG_OUT ("dpy = %p, DisplayString = \"%s\"", dpy, display);
1348 		LOCAL_DEBUG_OUT ("pid(%d), entered child process to spawn ...", pid);
1349 
1350 #if HAVE_DECL_ENVIRON
1351 		if (envvars == NULL) {
1352 			envvars = environ;
1353 		}
1354 #else
1355 /* how the hell could we get environment otherwise ? */
1356 #endif
1357 		if (envvars) {
1358 			int font_path_len = strlen (ASFONT_PATH_ENVVAR);
1359 			int image_path_len = strlen (ASIMAGE_PATH_ENVVAR);
1360 
1361 			for (env_s = 0; envvars[env_s] != NULL; ++env_s) {
1362 				if (font_path_slot < 0 && strlen (envvars[env_s]) > font_path_len)
1363 					if (strncmp (envvars[env_s], ASFONT_PATH_ENVVAR, font_path_len)
1364 							== 0)
1365 						font_path_slot = env_s;
1366 				if (image_path_slot < 0
1367 						&& strlen (envvars[env_s]) > image_path_len)
1368 					if (strncmp (envvars[env_s], ASIMAGE_PATH_ENVVAR, image_path_len)
1369 							== 0)
1370 						image_path_slot = env_s;
1371 			}
1372 		}
1373 		if (font_path_slot < 0)
1374 			++env_s;
1375 		if (image_path_slot < 0)
1376 			++env_s;
1377 		envp = safecalloc (env_s + 2, sizeof (char *));
1378 
1379 		/* environment variabless to pass to child process */
1380 		if (envvars) {
1381 			int dst = 0;
1382 
1383 			for (env_s = 0; envvars[env_s] != NULL; ++env_s) {
1384 				/* don't want to path DESKTOP_AUTOSTART_ID to our children -
1385 				   its set by gnome-session for AfterStep proper specifically,
1386 				   otherwise children will attempt to re-use it for SessionManagement registration, failing miserably */
1387 				if (strlen (envvars[env_s]) < sizeof (SESSION_ID_ENVVAR)
1388 						|| strncmp (envvars[env_s], SESSION_ID_ENVVAR,
1389 												sizeof (SESSION_ID_ENVVAR) - 1) != 0)
1390 					envp[dst++] = envvars[env_s];
1391 			}
1392 			env_s = dst;
1393 		}
1394 
1395 		envp[env_s] =
1396 				safemalloc (8 + strlen (orig_display ? orig_display : display) +
1397 										1);
1398 		sprintf (envp[env_s], "DISPLAY=%s",
1399 						 orig_display ? orig_display : display);
1400 		++env_s;
1401 		if (Environment) {
1402 			if (Environment->pixmap_path != NULL) {
1403 				int slot_no = image_path_slot;
1404 
1405 				if (slot_no < 0)
1406 					slot_no = env_s++;
1407 
1408 				envp[slot_no] =
1409 						safemalloc (strlen (ASIMAGE_PATH_ENVVAR) + 1 +
1410 												strlen (Environment->pixmap_path) + 1);
1411 				sprintf (envp[slot_no], "%s=%s", ASIMAGE_PATH_ENVVAR,
1412 								 Environment->pixmap_path);
1413 			}
1414 			if (Environment->font_path) {
1415 				int slot_no = font_path_slot;
1416 
1417 				if (slot_no < 0)
1418 					slot_no = env_s++;
1419 				envp[slot_no] =
1420 						safemalloc (strlen (ASFONT_PATH_ENVVAR) + 1 +
1421 												strlen (Environment->font_path) + 1);
1422 				sprintf (envp[slot_no], "%s=%s", ASFONT_PATH_ENVVAR,
1423 								 Environment->font_path);
1424 			}
1425 		}
1426 
1427 		len = strlen ((char *)cmd);
1428 		if (pass_args) {
1429 			register int i = 0;
1430 
1431 			while (display[i])
1432 				++i;
1433 
1434 			while (i > 0 && isdigit (display[--i])) ;
1435 			if (display[i] == '.')
1436 				display[i + 1] = '\0';
1437 /*
1438 			This bit of code seems to break AS restarting
1439 			on Fedora 8. causing DISPLAY=":0.0" to
1440 			become DISPLAY=":0.".  -- Jeremy
1441 */
1442 			if (screen >= 0)
1443 				screen_str = string_from_int (screen);
1444 			if (w != None)
1445 				w_str = string_from_int (w);
1446 			if (context != C_NO_CONTEXT)
1447 				context_str = string_from_int (context);
1448 
1449 			len += 1 + 2 + 1 + strlen (orig_display ? orig_display : display);
1450 			if (screen_str)
1451 				len += strlen (screen_str);
1452 			len += 3;									/* for "-s " */
1453 			if (get_flags (as_app_args.flags, ASS_Debugging))
1454 				len += 8;
1455 			if (get_flags (as_app_args.flags, ASS_Restarting))
1456 				len += 3;
1457 			if (as_app_args.override_config)
1458 				len += 4 + strlen (as_app_args.override_config);
1459 			if (as_app_args.override_home)
1460 				len += 4 + strlen (as_app_args.override_home);
1461 			if (as_app_args.override_share)
1462 				len += 4 + strlen (as_app_args.override_share);
1463 
1464 			if (as_app_args.locale)
1465 				len += 4 + strlen (as_app_args.locale);
1466 
1467 			if (as_app_args.verbosity_level != OUTPUT_DEFAULT_THRESHOLD)
1468 				len += 4 + 32;
1469 #ifdef DEBUG_TRACE_X
1470 			if (as_app_args.trace_calls)
1471 				len += 13 + strlen (as_app_args.trace_calls);
1472 #endif
1473 			if (w_str)
1474 				len += 1 + 8 + 1 + strlen (w_str);
1475 			if (context_str)
1476 				len += 1 + 9 + 1 + strlen (context_str);
1477 		}
1478 		/* now we want to append arbitrary number of arguments to the end of command line : */
1479 		va_start (ap, pass_args);
1480 		while ((arg = va_arg (ap, char *)) != NULL)
1481 			 len += 1 + strlen (arg);
1482 
1483 		va_end (ap);
1484 
1485 		len += 4;
1486 
1487 		ptr = cmdl = safemalloc (len);
1488 		strcpy (cmdl, (char *)cmd);
1489 		while (*ptr)
1490 			ptr++;
1491 		if (pass_args) {
1492 			if (orig_display)
1493 				ptr += sprintf (ptr, " -d %s -s", orig_display);
1494 			else if (screen_str)
1495 				ptr += sprintf (ptr, " -d %s.%s -s", display, screen_str);
1496 			else
1497 				ptr += sprintf (ptr, " -d %s -s", display);
1498 
1499 
1500 			if (get_flags (as_app_args.flags, ASS_Debugging)) {
1501 				strcpy (ptr, " --debug");
1502 				ptr += 8;
1503 			}
1504 			if (get_flags (as_app_args.flags, ASS_Restarting)) {
1505 				strcpy (ptr, " -r");
1506 				ptr += 3;
1507 			}
1508 			if (as_app_args.override_config)
1509 				ptr += sprintf (ptr, " -f %s", as_app_args.override_config);
1510 			if (as_app_args.override_home)
1511 				ptr += sprintf (ptr, " -p %s", as_app_args.override_home);
1512 			if (as_app_args.override_share)
1513 				ptr += sprintf (ptr, " -g %s", as_app_args.override_share);
1514 			if (as_app_args.verbosity_level != OUTPUT_DEFAULT_THRESHOLD)
1515 				ptr += sprintf (ptr, " -V %d", as_app_args.verbosity_level);
1516 			LOCAL_DEBUG_OUT
1517 					("len = %d, cmdl = \"%s\" strlen = %d, locale = \"%s\", ptr-cmdl = %d",
1518 					 len, cmdl, (int)strlen (cmdl), as_app_args.locale,
1519 					 (int)(ptr - cmdl));
1520 			if (as_app_args.locale && as_app_args.locale[0]
1521 					&& !isspace (as_app_args.locale[0]))
1522 				ptr += sprintf (ptr, " -L %s", as_app_args.locale);
1523 
1524 #ifdef DEBUG_TRACE_X
1525 			if (as_app_args.trace_calls)
1526 				ptr += sprintf (ptr, " --trace-func %s", as_app_args.trace_calls);
1527 #endif
1528 			if (w_str)
1529 				ptr += sprintf (ptr, " --window %s", w_str);
1530 			if (context_str)
1531 				ptr += sprintf (ptr, " --context %s", context_str);
1532 		}
1533 
1534 		va_start (ap, pass_args);
1535 		while ((arg = va_arg (ap, char *)) != NULL) {
1536 			*(ptr++) = ' ';
1537 			strcpy (ptr, arg);
1538 			while (*ptr)
1539 				ptr++;
1540 			LOCAL_DEBUG_OUT ("len = %d, cmdl = \"%s\" strlen = %d", len, cmdl,
1541 											 (int)strlen (cmdl));
1542 
1543 		}
1544 		va_end (ap);
1545 		if (do_fork) {
1546 			int i = ptr - cmdl;
1547 
1548 			while (--i >= 0)
1549 				if (!isspace (cmdl[i]))
1550 					break;
1551 			do_fork = (i < 0 || cmdl[i] != '&');
1552 		}
1553 		strcpy (ptr, do_fork ? " &\n" : "\n");
1554 
1555 		LOCAL_DEBUG_OUT ("len = %d, cmdl = \"%s\" strlen = %d", len, cmdl,
1556 										 (int)strlen (cmdl));
1557 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
1558 		{
1559 			FILE *fff = fopen ("/tmp/afterstep.exec.log", "a");
1560 
1561 			if (fff) {
1562 				fprintf (fff, "%s:%ld: [%s]", MyName, time (NULL), cmdl);
1563 				fclose (fff);
1564 			}
1565 		}
1566 #endif
1567 
1568 		LOCAL_DEBUG_OUT ("execle(\"%s\")", cmdl);
1569 		/* fprintf( stderr, "len=%d: execl(\"%s\")", len, cmdl ); */
1570 
1571 		/* CYGWIN does not handle close-on-exec gracefully - whave to do it ourselves : */
1572 		if (CloseOnExec)
1573 			CloseOnExec ();
1574 
1575 		{
1576 			const char *shell;
1577 			char *argv0;
1578 
1579 			if ((shell = getenv ("SHELL")) == NULL || *shell == '\0')
1580 				shell = mystrdup ("/bin/sh");
1581 
1582 			parse_file_name (shell, NULL, &argv0);
1583 			/* argv0 = basename(shell); */
1584 
1585 			execle (shell, argv0, "-c", cmdl, (char *)0, envp);
1586 		}
1587 
1588 		if (screen >= 0)
1589 			show_error ("failed to start %s on the screen %d", cmd, screen);
1590 		else
1591 			show_error ("failed to start %s", cmd);
1592 		show_system_error (" complete command line: \"%s\"\n", cmdl);
1593 		exit (128);
1594 	}
1595 }
1596 
1597 /******************************************************************************/
1598 /* web download functions : */
1599 /******************************************************************************/
is_url(const char * url)1600 Bool is_url (const char *url)
1601 {
1602 	return (strncmp (url, "http://", 7) == 0
1603 					|| strncmp (url, "ftp://", 6) == 0);
1604 }
1605 
make_log_name(const char * cachedFileName)1606 char *make_log_name (const char *cachedFileName)
1607 {
1608 	char *logName = safemalloc (strlen (cachedFileName) + 4 + 1);
1609 
1610 	sprintf (logName, "%s.log", cachedFileName);
1611 	return logName;
1612 }
1613 
spawn_download(const char * url,const char * cachedFileName)1614 int spawn_download (const char *url, const char *cachedFileName)
1615 {
1616 	/* cmdl: wget -b -nv -o <escaped_url>.log -O <cache_file> <url> */
1617 #define WGET_CMDL_HEADER "wget -b -nv -o "
1618 	int cacheFNLen = strlen (cachedFileName);
1619 	char *wget_cmdl =
1620 			safemalloc (sizeof (WGET_CMDL_HEADER) + cacheFNLen + 4 + 1 + 2 + 1 +
1621 									cacheFNLen + 1 + strlen (url) + 1);
1622 	int res;
1623 
1624 	sprintf (wget_cmdl, WGET_CMDL_HEADER "%s.log -O %s %s", cachedFileName,
1625 					 cachedFileName, url);
1626 	LOCAL_DEBUG_OUT ("spawning \"%s\"", wget_cmdl);
1627 	res =
1628 			spawn_child (wget_cmdl, -1, -1, NULL, None, C_NO_CONTEXT, True,
1629 									 False, NULL);
1630 	free (wget_cmdl);
1631 	return res;
1632 }
1633 
1634 Bool
check_download_complete(int pid,const char * cachedFileName,int * sizeDownloaded,int * size)1635 check_download_complete (int pid, const char *cachedFileName,
1636 												 int *sizeDownloaded, int *size)
1637 {
1638 	if (pid != 0) {
1639 		/* TODO : possibly check if process exited ? */
1640 
1641 	}
1642 	/* verify log file */
1643 	{
1644 		char *logName = make_log_name (cachedFileName);
1645 		char *log = logName ? load_file (logName) : NULL;
1646 
1647 		if (log && log[0] != '\0') {
1648 			int s1 = 0, s2 = 1;
1649 
1650 			char *openBracket = strchr (log, '[');
1651 
1652 			LOCAL_DEBUG_OUT ("Open Bracket:%s", openBracket);
1653 			if (openBracket) {
1654 				sscanf (openBracket + 1, "%d/%d", &s1, &s2);
1655 				LOCAL_DEBUG_OUT ("s1 = %d, s2 = %d", s1, s2);
1656 			}
1657 			if (sizeDownloaded)
1658 				*sizeDownloaded = s1;
1659 			if (size)
1660 				*size = s2;
1661 			free (log);
1662 			return True;
1663 		}
1664 	}
1665 	return False;
1666 }
1667 
1668 
1669 /************ end child process spawning ***************************/
1670