1 /*
2  * Copyright (c) 2005 Sasha Vasko <sasha at aftercode.net>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
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 
21 /* #define LOCAL_DEBUG */
22 /*#define DO_CLOCKING */
23 
24 #include "../configure.h"
25 
26 #include <unistd.h>
27 
28 #include "../libAfterStep/asapp.h"
29 #include "../libAfterStep/afterstep.h"
30 #include "../libAfterStep/session.h"
31 #include "../libAfterStep/desktop_category.h"
32 
33 #include "afterconf.h"
34 
35 const char *default_aliases[][2] = {
36 	{"ArcadeGame", "Arcade"},
37 	{"Application", "Applications"},
38 	{"Game", "Games"},
39 	{"Utility", "Utilities"},
40 	{NULL, NULL}
41 
42 };
43 
44 
45 /*************************************************************************/
46 /* private stuff : 													 */
47 /*************************************************************************/
48 #if 0
49 static char **parse_category_list (char *list, int *pnum_return)
50 {
51 	char **shortcuts = NULL;
52 	int num = 0;
53 
54 	if (list) {
55 		int i;
56 
57 		for (i = 0; list[i]; ++i)
58 			if (list[i] == ';')
59 				++num;
60 		if (i > 0 && list[i - 1] != ';')
61 			++num;
62 		if (num > 0) {
63 			int sc_i = 0;
64 
65 			shortcuts = safecalloc (num + 1, sizeof (char *));
66 
67 			shortcuts[sc_i++] = &list[0];
68 			for (i = 0; list[i]; ++i)
69 				if (list[i] == ';') {
70 					list[i++] = '\0';
71 					if (list[i] == '\0' || sc_i >= num)
72 						break;
73 					shortcuts[sc_i++] = &list[i];
74 				}
75 		}
76 	}
77 	if (pnum_return)
78 		*pnum_return = num;
79 	return shortcuts;
80 }
81 #endif
82 
filter_desktop_entry_exec(const char * exec)83 static char *filter_desktop_entry_exec (const char *exec)
84 {
85 	char *clean_exec = mystrdup (exec);
86 	int start = 0, ts;
87 
88 	while (clean_exec[start] != '\0' && !isspace (clean_exec[start]))
89 		++start;
90 	while (clean_exec[start] != '\0') {
91 		ts = start;
92 		while (isspace (clean_exec[ts]))
93 			++ts;
94 		if (clean_exec[ts] == '%' && isalpha (clean_exec[ts + 1])) {
95 			while (!isspace (clean_exec[ts]) && clean_exec[ts] != '\0') {
96 				clean_exec[ts] = ' ';
97 				++ts;
98 			}
99 			start = ts;
100 		} else if (mystrncasecmp (&clean_exec[ts], "-caption ", 9) == 0) {
101 			ts += 9;
102 			while (isspace (clean_exec[ts]))
103 				++ts;
104 			if (mystrncasecmp (&clean_exec[ts], "\"%c\"", 4) == 0) {
105 				ts += 3;
106 				while (start < ts)
107 					clean_exec[++start] = ' ';
108 			} else if (clean_exec[ts] == '%' && isalpha (clean_exec[ts + 1])) {
109 				ts += 1;
110 				while (start < ts)
111 					clean_exec[++start] = ' ';
112 			}
113 		} else if (clean_exec[ts] == '\"') {
114 			char *end = find_doublequotes (&clean_exec[ts]);
115 
116 			if (end != NULL)
117 				start = end - &clean_exec[0];
118 			else
119 				start = ts;
120 			++start;
121 		} else
122 			for (start = ts;
123 					 !isspace (clean_exec[start]) && clean_exec[start] != '\0';
124 					 ++start) ;
125 	}
126 	while (isspace (clean_exec[start - 1])) {
127 		--start;
128 		clean_exec[start] = '\0';
129 	}
130 	return clean_exec;
131 }
132 
stripcpy_localized(char * ptr)133 char *stripcpy_localized (char *ptr)
134 {
135 	int i = 0;
136 	static char default_locale[] = "us";
137 	char *locale = MyArgs.locale[0] ? MyArgs.locale : &default_locale[0];
138 
139 	while (locale[i] != '.' && locale[i] != '\0' && ptr[i] != ']') {
140 		if (ptr[i] != locale[i])
141 			break;
142 		++i;
143 	}
144 	if ((locale[i] == '.' || locale[i] == '_' || locale[i] == '\0')
145 			&& ptr[i] == ']')
146 		return stripcpy (ptr + i + 2);
147 	return NULL;
148 }
149 
parse_desktop_entry_line(ASDesktopEntry * de,char * ptr)150 static void parse_desktop_entry_line (ASDesktopEntry * de, char *ptr)
151 {
152 #define PARSE_ASDE_TYPE_VAL(val)	if(mystrncasecmp(ptr, #val, ASDE_KEYWORD_##val##_LEN) == 0){de->type = ASDE_Type##val; return;}
153 #define PARSE_ASDE_STRING_VAL(val)	if(mystrncasecmp(ptr, #val "=", ASDE_KEYWORD_##val##_LEN+1) == 0){if( de->val ) free( de->val ) ; de->val = stripcpy(ptr+ASDE_KEYWORD_##val##_LEN+1); return;}
154 #define PARSE_ASDE_FLAG_VAL(val)	if(mystrncasecmp(ptr, #val "=", ASDE_KEYWORD_##val##_LEN+1) == 0){char *tmp = stripcpy(ptr+ASDE_KEYWORD_##val##_LEN+1); if( tmp[0] == '1' || mystrcasecmp(tmp, "true") == 0 ) set_flags(de->flags, ASDE_##val); free(tmp); return;}
155 
156 	if (ptr[0] == 'X' && ptr[1] == '-') {
157 		ptr += 2;
158 		if (mystrncasecmp (ptr, "AfterStep-", 10) == 0) {
159 			ptr += 10;
160 			PARSE_ASDE_STRING_VAL (IndexName)
161 					PARSE_ASDE_STRING_VAL (Aliases)
162 					PARSE_ASDE_FLAG_VAL (ASModule)
163 		PARSE_ASDE_FLAG_VAL (CheckAvailability)} else
164 				if (mystrncasecmp (ptr, "KDE-", 4) == 0)
165 			set_flags (de->flags, ASDE_KDE);
166 		else if (mystrncasecmp (ptr, "GNOME-", 6) == 0)
167 			set_flags (de->flags, ASDE_GNOME);
168 	} else if (mystrncasecmp (ptr, "Name[", 5) == 0
169 						 && MyArgs.locale[0] == ptr[5]) {
170 		char *val = stripcpy_localized (ptr + 5);
171 
172 		if (val)
173 			set_string (&(de->Name_localized), val);
174 	} else if (mystrncasecmp (ptr, "Type=", 5) == 0) {
175 		ptr += 5;
176 
177 		PARSE_ASDE_TYPE_VAL (Application)
178 				PARSE_ASDE_TYPE_VAL (Link)
179 				PARSE_ASDE_TYPE_VAL (FSDevice)
180 	PARSE_ASDE_TYPE_VAL (Directory)} else
181 			if (mystrncasecmp (ptr, "Comment[", 8) == 0
182 					&& MyArgs.locale[0] == ptr[8]) {
183 		char *val = stripcpy_localized (ptr + 8);
184 
185 		if (val)
186 			set_string (&(de->Comment_localized), val);
187 	} else if (mystrncasecmp (ptr, "Encoding=", 9) == 0
188 						 && mystrncasecmp (ptr + 9, "UTF-8", 5) != 0) {
189 		set_flags (de->flags, ASDE_EncodingNonUTF8);
190 	} else {
191 		PARSE_ASDE_STRING_VAL (Name)
192 				PARSE_ASDE_STRING_VAL (GenericName)
193 				PARSE_ASDE_STRING_VAL (Comment)
194 				PARSE_ASDE_STRING_VAL (Icon)
195 				PARSE_ASDE_STRING_VAL (TryExec)
196 				PARSE_ASDE_STRING_VAL (Exec)
197 				PARSE_ASDE_STRING_VAL (Path)
198 				PARSE_ASDE_STRING_VAL (SwallowTitle)
199 				PARSE_ASDE_STRING_VAL (SwallowExec)
200 				PARSE_ASDE_STRING_VAL (SortOrder)
201 				PARSE_ASDE_STRING_VAL (Categories)
202 				PARSE_ASDE_STRING_VAL (OnlyShowIn)
203 				PARSE_ASDE_STRING_VAL (NotShowIn)
204 				PARSE_ASDE_STRING_VAL (StartupWMClass)
205 				PARSE_ASDE_FLAG_VAL (NoDisplay)
206 	PARSE_ASDE_FLAG_VAL (Hidden) PARSE_ASDE_FLAG_VAL (Terminal)
207 				PARSE_ASDE_FLAG_VAL (StartupNotify)}
208 }
209 
210 static void
fix_desktop_entry(ASDesktopEntry * de,const char * default_category,const char * icon_path,const char * origin,Bool applnk)211 fix_desktop_entry (ASDesktopEntry * de, const char *default_category,
212 									 const char *icon_path, const char *origin, Bool applnk)
213 {
214 	if (de->Categories == NULL && default_category) {
215 		if (get_flags (de->flags, ASDE_KDE | ASDE_GNOME) == 0) {
216 			if (mystrncasecmp (default_category, "KDE", 3) == 0)
217 				set_flags (de->flags, ASDE_KDE);
218 			else if (mystrncasecmp (default_category, "GNOME", 5) == 0)
219 				set_flags (de->flags, ASDE_GNOME);
220 		}
221 		if (de->type != ASDE_TypeDirectory)
222 			de->Categories = mystrdup (default_category);
223 	}
224 	if (applnk)
225 		set_flags (de->flags, ASDE_KDE);
226 
227 	if (de->Categories != NULL) {
228 		de->categories_len = strlen (de->Categories);
229 		de->categories_shortcuts =
230 				compound_string2string_list (de->Categories, ';', False,
231 																		 &(de->categories_num));
232 		if (get_flags (de->flags, ASDE_KDE | ASDE_GNOME) == 0) {
233 			int i = de->categories_num;
234 			ASFlagType kind = 0;
235 
236 			while (--i >= 0 && kind == 0) {
237 				char *ptr = de->categories_shortcuts[i];
238 
239 				if (ptr[0] == 'X') {
240 					if (ptr[1] != '-')
241 						continue;
242 					ptr += 2;
243 				}
244 				if (mystrncasecmp (ptr, "KDE", 3) == 0)
245 					set_flags (kind, ASDE_KDE);
246 				else if (mystrncasecmp (ptr, "GNOME", 5) == 0)
247 					set_flags (kind, ASDE_GNOME);
248 			}
249 			set_flags (de->flags, kind);
250 		}
251 	}
252 	if (get_flags (de->flags, ASDE_KDE | ASDE_GNOME) == 0 && de->Name) {
253 		if (de->Name[0] == 'G')
254 			set_flags (de->flags, ASDE_GNOME);
255 		else if (de->Name[0] == 'K')
256 			set_flags (de->flags, ASDE_KDE);
257 	}
258 	if (de->Aliases != NULL) {
259 		de->aliases_len = strlen (de->Aliases);
260 		de->aliases_shortcuts =
261 				compound_string2string_list (de->Aliases, ';', False,
262 																		 &(de->aliases_num));
263 	}
264 
265 	if (de->OnlyShowIn != NULL) {
266 		de->show_in_len = strlen (de->OnlyShowIn);
267 		de->show_in_shortcuts =
268 				compound_string2string_list (de->OnlyShowIn, ';', False,
269 																		 &(de->show_in_num));
270 	}
271 	if (de->NotShowIn != NULL) {
272 		de->not_show_in_len = strlen (de->NotShowIn);
273 		de->not_show_in_shortcuts =
274 				compound_string2string_list (de->NotShowIn, ';', False,
275 																		 &(de->not_show_in_num));
276 	}
277 	if (de->Exec)
278 		de->clean_exec = filter_desktop_entry_exec (de->Exec);
279 
280 	de->origin = mystrdup (origin);
281 
282 	if (get_flags (de->flags, ASDE_CheckAvailability)) {
283 		if (!is_executable_in_path (de->clean_exec))
284 			set_flags (de->flags, ASDE_Unavailable);
285 		LOCAL_DEBUG_OUT
286 				("checking availability(clean_exec) for \"%s\" - %s available",
287 				 de->clean_exec,
288 				 (get_flags (de->flags, ASDE_Unavailable) ? "not" : ""));
289 	} else if (de->TryExec != NULL) {
290 		if (!is_executable_in_path (de->TryExec))
291 			set_flags (de->flags, ASDE_Unavailable);
292 		LOCAL_DEBUG_OUT
293 				("checking availability(TryExec) for \"%s\" - %s available",
294 				 de->clean_exec,
295 				 (get_flags (de->flags, ASDE_Unavailable) ? "not" : ""));
296 	}
297 
298 }
299 
parse_desktop_entry(const char * fullfilename,const char * default_category,ASDesktopEntryTypes default_type,const char * icon_path,Bool applnk)300 static ASDesktopEntry *parse_desktop_entry (const char *fullfilename,
301 																						const char *default_category,
302 																						ASDesktopEntryTypes
303 																						default_type,
304 																						const char *icon_path,
305 																						Bool applnk)
306 {
307 	ASDesktopEntry *de = NULL;
308 	FILE *fp = NULL;
309 
310 	if (fullfilename)
311 		fp = fopen (fullfilename, "r");
312 
313 	if (fp) {
314 		static char rb[MAXLINELENGTH + 1];
315 
316 		de = create_desktop_entry (default_type);
317 		while (fgets (&(rb[0]), MAXLINELENGTH, fp) != NULL)
318 			parse_desktop_entry_line (de, &(rb[0]));
319 		fix_desktop_entry (de, default_category, icon_path, fullfilename,
320 											 applnk);
321 		fclose (fp);
322 	}
323 	return de;
324 }
325 
326 int
parse_desktop_entry_list(const char * fullfilename,ASBiDirList * entry_list,const char * default_category,ASDesktopEntryTypes default_type,const char * icon_path,Bool applnk)327 parse_desktop_entry_list (const char *fullfilename,
328 													ASBiDirList * entry_list,
329 													const char *default_category,
330 													ASDesktopEntryTypes default_type,
331 													const char *icon_path, Bool applnk)
332 {
333 	ASDesktopEntry *de = NULL;
334 	int count = 0;
335 	FILE *fp = NULL;
336 
337 	/*LOCAL_DEBUG_OUT( "PARSING \"%s\"", fullfilename );    */
338 	if (fullfilename)
339 		fp = fopen (fullfilename, "r");
340 
341 	if (fp) {
342 		static char rb[MAXLINELENGTH + 1];
343 
344 		while (fgets (&(rb[0]), MAXLINELENGTH, fp) != NULL) {
345 			/*LOCAL_DEBUG_OUT( "rb = \"%s\", de = %p", &(rb[0]), de ); */
346 			if (rb[0] == '[') {
347 				if ((rb[1] == 'D'
348 						 && (mystrncasecmp (&(rb[2]), "esktop Entry]", 13) == 0
349 								 || mystrncasecmp (&(rb[2]), "esktopEntry]", 12) == 0))
350 						|| (rb[1] == 'K'
351 								&& mystrncasecmp (&(rb[2]), "DE Desktop Entry]",
352 																	17) == 0)) {
353 					if (de) {
354 						fix_desktop_entry (de, default_category, icon_path,
355 															 fullfilename, applnk);
356 						append_bidirelem (entry_list, de);
357 					}
358 					de = create_desktop_entry (default_type);
359 					++count;
360 				} else if (de) {
361 					fix_desktop_entry (de, default_category, icon_path, fullfilename,
362 														 applnk);
363 					append_bidirelem (entry_list, de);
364 					de = NULL;
365 				}
366 			} else if (de)
367 				parse_desktop_entry_line (de, &(rb[0]));
368 		}
369 		if (de) {
370 			fix_desktop_entry (de, default_category, icon_path, fullfilename,
371 												 applnk);
372 			append_bidirelem (entry_list, de);
373 		}
374 		fclose (fp);
375 	}
376 	return count;
377 }
378 
379 
380 
381 static void
parse_desktop_entry_tree(char * fullpath,const char * dirname,ASBiDirList * entry_list,ASDesktopEntry * parent,const char * icon_path,const char * default_app_category,Bool applnk)382 parse_desktop_entry_tree (char *fullpath, const char *dirname,
383 													ASBiDirList * entry_list,
384 													ASDesktopEntry * parent, const char *icon_path,
385 													const char *default_app_category, Bool applnk)
386 {
387 	struct direntry **list = NULL;
388 	int list_len, i, curr_dir_index = -1;
389 	char *dir_category = NULL;
390 	ASDesktopEntry *tmp, *curr_dir = NULL;
391 
392 
393 	list_len = my_scandir (fullpath, &list, no_dots_except_directory, NULL);
394 
395 	fprintf (stderr, "number of items in %s = %d\n", fullpath, list_len);
396 	for (i = 0; i < list_len; i++) {
397 		if (!S_ISDIR (list[i]->d_mode) && list[i]->d_name[0] == '.') {
398 			if (strcasecmp (list[i]->d_name, ".directory") == 0) {
399 				curr_dir_index = i;
400 				tmp =
401 						parse_desktop_entry (fullpath, parent ? parent->Name : NULL,
402 																 ASDE_TypeDirectory, icon_path, applnk);
403 				if (tmp) {
404 					if (tmp->Name == NULL)
405 						tmp->Name = mystrdup (dirname);
406 					if (mystrcasecmp (tmp->Name, DEFAULT_DESKTOP_CATEGORY_NAME) != 0)
407 						dir_category = mystrdup (tmp->Name);
408 					curr_dir = tmp;
409 					append_bidirelem (entry_list, tmp);
410 				}
411 				break;
412 			}
413 		}
414 	}
415 	if (curr_dir == NULL) {
416 		curr_dir =
417 				parse_desktop_entry (fullpath, parent ? parent->Name : NULL,
418 														 ASDE_TypeDirectory, icon_path, applnk);
419 		if (curr_dir) {
420 			if (curr_dir->Name == NULL) {
421 				curr_dir->Name = mystrdup (dirname);
422 				append_bidirelem (entry_list, curr_dir);
423 			}
424 		}
425 	}
426 	for (i = 0; i < list_len; i++) {
427 		if (list[i]->d_name[0] != '.') {
428 			char *entry_fullpath = make_file_name (fullpath, list[i]->d_name);
429 
430 			if (S_ISDIR (list[i]->d_mode)) {
431 /*fprintf(stderr, "Parsing subtree %s.\n", entry_fullpath);*/
432 				parse_desktop_entry_tree (entry_fullpath, list[i]->d_name,
433 																	entry_list, curr_dir, icon_path,
434 																	default_app_category, applnk);
435 			} else if (i != curr_dir_index) {
436 /*fprintf(stderr, "Parsing subitem %s.\n", entry_fullpath);*/
437 				parse_desktop_entry_list (entry_fullpath, entry_list,
438 																	dir_category ? dir_category :
439 																	default_app_category,
440 																	ASDE_TypeApplication, icon_path, applnk);
441 			}
442 			free (entry_fullpath);
443 		}
444 		free (list[i]);
445 	}
446 
447 	if (list)
448 		free (list);
449 
450 	if (dir_category)
451 		free (dir_category);
452 }
453 
desktop_entry_destroy_list_item(void * data)454 static void desktop_entry_destroy_list_item (void *data)
455 {
456 	unref_desktop_entry ((ASDesktopEntry *) data);
457 }
458 
register_desktop_entry_list_item(void * data,void * aux_data)459 static Bool register_desktop_entry_list_item (void *data, void *aux_data)
460 {
461 	register_desktop_entry ((ASCategoryTree *) aux_data,
462 													(ASDesktopEntry *) data);
463 	return True;
464 }
465 
466 /*************************************************************************/
467 /* public methods : 													 */
468 /*************************************************************************/
469 
load_category_tree(ASCategoryTree * ct)470 Bool load_category_tree (ASCategoryTree * ct)
471 {
472 	if (ct && ct->dir_list) {
473 		int i;
474 		ASBiDirList *entry_list =
475 				create_asbidirlist (desktop_entry_destroy_list_item);
476 
477 		for (i = 0; i < ct->dir_num; ++i) {
478 			Bool applnk = (strstr (ct->dir_list[i], "/applnk") != NULL);
479 
480 			if (CheckDir (ct->dir_list[i]) == 0) {
481 /*				fprintf( stderr, "location : \"%s\", applnk == %d\n", ct->dir_list[i], applnk );
482 */
483 				parse_desktop_entry_tree (ct->dir_list[i], NULL, entry_list, NULL,
484 																	ct->icon_path, ct->name, applnk);
485 			} else if (CheckFile (ct->dir_list[i]) == 0)
486 				parse_desktop_entry_list (ct->dir_list[i], entry_list, ct->name,
487 																	ASDE_TypeDirectory, ct->icon_path,
488 																	applnk);
489 		}
490 		LOCAL_DEBUG_OUT ("Done parsing for tree %s", ct->name);
491 		iterate_asbidirlist (entry_list, register_desktop_entry_list_item, ct,
492 												 NULL, False);
493 		destroy_asbidirlist (&entry_list);
494 /*		flush_asbidirlist_memory_pool(); */
495 /*		print_unfreed_mem (); */
496 		return True;
497 	}
498 	return False;
499 }
500 
DestroyCategories()501 void DestroyCategories ()
502 {
503 	if (StandardCategories)
504 		destroy_category_tree (&StandardCategories);
505 	if (AfterStepCategories)
506 		destroy_category_tree (&AfterStepCategories);
507 	if (KDECategories)
508 		destroy_category_tree (&KDECategories);
509 	if (GNOMECategories)
510 		destroy_category_tree (&GNOMECategories);
511 	if (OtherCategories)
512 		destroy_category_tree (&OtherCategories);
513 	if (CombinedCategories)
514 		destroy_category_tree (&CombinedCategories);
515 #ifdef DEBUG_ALLOCS
516 /*	print_unfreed_mem (); */
517 #endif													/* DEBUG_ALLOCS */
518 }
519 
save_category_tree_cache(ASCategoryTree * ct,const char * fname)520 void save_category_tree_cache (ASCategoryTree * ct, const char *fname)
521 {
522 	char *configfile;
523 	FILE *fp;
524 
525 	configfile = make_session_data_file (Session, False, 0, fname, NULL);
526 	if (configfile) {
527 		fp = fopen (configfile, "wb");
528 		if (fp) {
529 			save_category_tree (ct, fp);
530 			fclose (fp);
531 		}
532 		free (configfile);
533 	}
534 }
535 
UpdateCategoriesCache()536 void UpdateCategoriesCache ()
537 {
538 	save_category_tree_cache (AfterStepCategories, AFTERSTEP_CACHE_FILE);
539 	save_category_tree_cache (KDECategories, KDE_CACHE_FILE);
540 	save_category_tree_cache (GNOMECategories, GNOME_CACHE_FILE);
541 	save_category_tree_cache (OtherCategories, OTHER_CACHE_FILE);
542 }
543 
ReloadCategories(Bool cached)544 void ReloadCategories (Bool cached)
545 {
546 	char *configfile;
547 
548 	START_TIME (started);
549 
550 	DestroyCategories ();
551 
552 	if ((configfile =
553 			 make_session_file (Session, STANDARD_CATEGORIES_FILE,
554 													False)) != NULL) {
555 		StandardCategories =
556 				create_category_tree ("Default", configfile,
557 															Environment ? Environment->
558 															pixmap_path : NULL, 0, -1);
559 		free (configfile);
560 	}
561 
562 	if (cached) {
563 		char *configfile =
564 				make_session_data_file (Session, False, 0, AFTERSTEP_CACHE_FILE,
565 																NULL);
566 
567 		AfterStepCategories =
568 				create_category_tree ("AfterStep", configfile,
569 															Environment ? Environment->
570 															pixmap_path : NULL, 0, -1);
571 		free (configfile);
572 		configfile =
573 				make_session_data_file (Session, False, 0, KDE_CACHE_FILE, NULL);
574 		KDECategories =
575 				create_category_tree ("KDE", configfile, KDE_ICONS_PATH, 0, -1);
576 		free (configfile);
577 		configfile =
578 				make_session_data_file (Session, False, 0, GNOME_CACHE_FILE, NULL);
579 		GNOMECategories =
580 				create_category_tree ("GNOME", configfile, GNOME_ICONS_PATH, 0,
581 															-1);
582 		free (configfile);
583 		configfile =
584 				make_session_data_file (Session, False, 0, OTHER_CACHE_FILE, NULL);
585 		OtherCategories =
586 				create_category_tree ("OTHER", configfile, OTHER_ICONS_PATH, 0,
587 															-1);
588 		free (configfile);
589 	} else {
590 		char *path = make_session_apps_path (Session);
591 
592 		if (path) {
593 			AfterStepCategories =
594 					create_category_tree ("AfterStep", path,
595 																Environment ? Environment->
596 																pixmap_path : NULL, 0, -1);
597 			free (path);
598 		}
599 
600 		KDECategories =
601 				create_category_tree ("KDE", KDE_APPS_PATH, KDE_ICONS_PATH,
602 															ASCT_OnlyKDE, -1);
603 		GNOMECategories =
604 				create_category_tree ("GNOME", GNOME_APPS_PATH, GNOME_ICONS_PATH,
605 															ASCT_OnlyGNOME, -1);
606 		OtherCategories =
607 				create_category_tree ("OTHER", OTHER_APPS_PATH, OTHER_ICONS_PATH,
608 															ASCT_ExcludeGNOME | ASCT_ExcludeKDE, -1);
609 
610 	}
611 
612 	CombinedCategories = create_category_tree ("", NULL, NULL, 0, -1);
613 
614 	load_category_tree (StandardCategories);
615 	SHOW_TIME ("Standard categories", started);
616 	if (!cached) {
617 		add_category_tree_subtree (AfterStepCategories, StandardCategories);
618 		add_category_tree_subtree (KDECategories, StandardCategories);
619 		add_category_tree_subtree (GNOMECategories, StandardCategories);
620 		add_category_tree_subtree (OtherCategories, StandardCategories);
621 	}
622 	load_category_tree (AfterStepCategories);
623 	SHOW_TIME ("AfterStep categories", started);
624 	load_category_tree (KDECategories);
625 	SHOW_TIME ("KDE categories", started);
626 	load_category_tree (GNOMECategories);
627 	SHOW_TIME ("GNOME categories", started);
628 	load_category_tree (OtherCategories);
629 	SHOW_TIME ("Other categories", started);
630 
631 	LOCAL_DEBUG_OUT
632 			("@ Building up Combined: @@@@@@@@@@@@@@@@@@@@@@@@@@@@%s", "");
633 
634 	add_category_tree_subtree (CombinedCategories, StandardCategories);
635 	add_category_tree_subtree (CombinedCategories, AfterStepCategories);
636 	add_category_tree_subtree (CombinedCategories, KDECategories);
637 	add_category_tree_subtree (CombinedCategories, GNOMECategories);
638 	add_category_tree_subtree (CombinedCategories, OtherCategories);
639 
640 	SHOW_TIME (__FUNCTION__, started);
641 }
642 
643 
644 #ifdef PRINT_DESKTOP_ENTRIES
main(int argc,char ** argv)645 int main (int argc, char **argv)
646 {
647 	int i;
648 	ASDesktopCategory *dc = NULL;
649 	ASCategoryTree *ct = NULL;
650 	Bool cached = False;
651 
652 	InitMyApp ("PrintDesktopEntries", argc, argv, NULL, NULL, 0);
653 	InitSession ();
654 	for (i = 1; i < argc; ++i)
655 		if (argv[i] && strcmp (argv[i], "--cached") == 0)
656 			cached = True;
657 
658 	ReloadCategories (cached);
659 
660 	for (i = 1; i < argc; ++i)
661 		if (argv[i] && strcmp (argv[i], "--cached") != 0) {
662 			char *name = NULL;
663 			char *colon = strchr (argv[i], ':');
664 			int len = strlen (argv[i]);
665 
666 			if (colon == NULL) {
667 				name = safemalloc (len + 1 + 7 + 1);
668 				sprintf (name, "%s:Default", argv[i]);
669 			} else if (colon[1] == '\0') {
670 				name = safemalloc (len + 7 + 1);
671 				sprintf (name, "%sDefault", argv[i]);
672 			} else
673 				name = mystrdup (argv[i]);
674 
675 			dc = name2desktop_category (name, &ct);
676 			if (dc == NULL) {
677 				fprintf (stderr, "Invalid category name \"%s\"", argv[i]);
678 				return 0;
679 			}
680 			free (name);
681 			break;
682 		}
683 	if (dc && ct) {
684 		print_category_tree2 (ct, dc);
685 
686 	} else {
687 		fprintf (stderr,
688 						 "#Standard: ####################################################\n");
689 		print_category_tree2 (StandardCategories, NULL);
690 		fprintf (stderr,
691 						 "#AfterStep:####################################################\n");
692 		print_category_tree2 (AfterStepCategories, NULL);
693 		fprintf (stderr,
694 						 "#KDE:      ####################################################\n");
695 		print_category_tree2 (KDECategories, NULL);
696 		fprintf (stderr,
697 						 "#GNOME:    ####################################################\n");
698 		print_category_tree2 (GNOMECategories, NULL);
699 		fprintf (stderr,
700 						 "#OTHER:   ####################################################\n");
701 		print_category_tree2 (OtherCategories, NULL);
702 		fprintf (stderr,
703 						 "#Combined: ####################################################\n");
704 		print_category_tree2 (CombinedCategories, NULL);
705 		fprintf (stderr,
706 						 "#####################################################\n");
707 	}
708 	DestroyCategories ();
709 	FreeMyAppResources ();
710 	return 1;
711 }
712 
713 #else
714 #ifdef TEST_AS_DESKTOP_ENTRY
715 
716 #define REDHAT_APPLNK	"/etc/X11/applnk"
717 #define DEBIAN_APPLNK	"/usr/share/applications"
718 
719 /*
720  * From e-mail :
721  * The paths to the directories should be given by the DESKTOP_FILE_PATH
722  * enviromental variable if other directories then /usr/share/applications/ are
723  * needed.  This environment variable has the same format as the PATH
724  * evironment variable, ':'separating entries.  If DESKTOP_FILE_PATH is present,
725  * /usr/share/applications is not checked by default, and thus shoul dbe included
726  * in the path.
727  *
728  * see: https://listman.redhat.com/archives/xdg-list/2002-July/msg00049.html
729  * 		http://standards.freedesktop.org/menu-spec/menu-spec-0.9.html#paths
730  * 		http://www.freedesktop.org/Standards/desktop-entry-spec
731 */
732 
main(int argc,char ** argv)733 int main (int argc, char **argv)
734 {
735 
736 
737 //  ASBiDirList *entry_list = create_asbidirlist( desktop_entry_destroy_list_item );
738 
739 	InitMyApp ("TestASDesktopEntry", argc, argv, NULL, NULL, 0);
740 	InitSession ();
741 	ReloadCategories (False);
742 //  ReloadCategories();
743 //  ReloadCategories();
744 
745 	fprintf (stderr,
746 					 "#Standard: ####################################################\n");
747 	print_category_tree2 (StandardCategories, NULL);
748 	fprintf (stderr,
749 					 "#AfterStep: ####################################################\n");
750 	print_category_tree2 (AfterStepCategories, NULL);
751 	fprintf (stderr,
752 					 "#KDE: ####################################################\n");
753 	print_category_tree2 (KDECategories, NULL);
754 	fprintf (stderr,
755 					 "#GNOME: ####################################################\n");
756 	print_category_tree2 (GNOMECategories, NULL);
757 	fprintf (stderr,
758 					 "#OTHER: ####################################################\n");
759 	print_category_tree2 (OtherCategories, NULL);
760 	fprintf (stderr,
761 					 "#Combined: ####################################################\n");
762 	print_category_tree2 (CombinedCategories, NULL);
763 	fprintf (stderr,
764 					 "#####################################################\n");
765 
766 	DestroyCategories ();
767 	FreeMyAppResources ();
768 #ifdef DEBUG_ALLOCS
769 	print_unfreed_mem ();
770 #endif													/* DEBUG_ALLOCS */
771 	return 1;
772 }
773 #else
774 #ifdef MAKE_STANDARD_CATEGORIES
775 /* helper app to generate set of .desktop files for the list */
main(int argc,char ** argv)776 int main (int argc, char **argv)
777 {
778 	char *doc_str;
779 	xml_elem_t *doc;
780 	xml_elem_t *tr, *td;
781 
782 
783 
784 	if (argc < 2) {
785 		show_error ("Usage: make_standard_categories <source_file_name>\n");
786 		exit (1);
787 	}
788 
789 	doc_str = load_file (argv[1]);
790 	if (!doc_str) {
791 		show_error ("Unable to load file [%s]: %s.\n", argv[1],
792 								strerror (errno));
793 		exit (1);
794 	}
795 
796 	doc = xml_parse_doc (doc_str, NULL);
797 	if (!doc) {
798 		show_error ("Unable to parse data: %s.\n", strerror (errno));
799 		exit (1);
800 	}
801 
802 	for (tr = doc->child; tr; tr = tr->next) {
803 		if (strcmp (tr->tag, "tr") == 0) {
804 			char *name = NULL, *parent = NULL, *comment = NULL;
805 
806 			td = tr->child;
807 			if (td && td->child && strcmp (td->child->tag, XML_CDATA_STR) == 0) {
808 				name = td->child->parm;
809 				td = td->next;
810 				if (td) {
811 					if (td->child && strcmp (td->child->tag, XML_CDATA_STR) == 0)
812 						comment = td->child->parm;
813 					td = td->next;
814 					if (td && td->child
815 							&& strcmp (td->child->tag, XML_CDATA_STR) == 0)
816 						parent = td->child->parm;
817 				}
818 			}
819 			if (name && strlen (name) < 200) {
820 				char filename[1024];
821 				FILE *fp;
822 
823 				sprintf (filename, "categories/%s.desktop", name);
824 				fp = fopen (filename, "wt");
825 				if (fp) {
826 					fprintf (fp, "[DesktopEntry]\nName=%s\n", name);
827 					fprintf (fp, "X-AfterStep-IndexName=%s\n", name);
828 					fprintf (fp, "Categories=%s\n", parent ? parent : "");
829 					fprintf (fp, "Comment=%s\n", comment ? comment : "");
830 					fclose (fp);
831 				}
832 			}
833 
834 		}
835 	}
836 
837 	return 1;
838 }
839 #endif
840 #endif
841 #endif
842