1 /*
2  * Copyright (C) 1997 Red Hat Software, Inc.
3  *	Written for afterstep by Cristian Gafton <gafton@redhat.com>
4  *	Modified for KDE by Kevin Vajk <kvajk@ricochet.net>
5  *
6  * Modify: 2015/11/26 Tommy Scheunemann <net@arrishq.net>
7  *
8  * Modify: 2014/01/07 Tommy Scheunemann <net@arrishq.net>
9  *
10  * Modify: 2013/07/03 Tommy Scheunemann <net@arrishq.net>
11  *
12  * Modify: 2013/03/19 Tommy Scheunemann <net@arrishq.net>
13  *
14  * Modify: 2013/01/06 Tommy Scheunemann <net@arrishq.net>
15  *
16  * Modify: 2012/12/18 Tommy Scheunemann <net@arrishq.net>
17  *
18  * Modify: 2010/12/27 Tommy Scheunemann <net@arrishq.net>
19  *
20  * Modify: 2008/21/01 Tommy Scheunemann <net@arrishq.net>
21  *
22  * Modify: 2006/24/10 Tommy Scheunemann <net@arrishq.net>
23  *
24  * Modify: 2005/12/10 Tommy Scheunemann <net@arrishq.net>
25  *
26  * Modify: 2005/01/11 Tommy Scheunemann <net@arrishq.net>
27  *
28  * Modify: 2004/08/09 Tommy Scheunemann <net@arrishq.net>
29  *
30  * Modify: 2004/07/10 Tommy Scheunemann <net@arrishq.net>
31  *
32  * Modify: 2003/11/19 Tommy Scheunemann <net@arrishq.org>
33  *
34  *
35  * This program is free software; you can redistribute it and/or modify
36  * it under the terms of the GNU General Public License as published by
37  * the Free Software Foundation; either version 2 of the License, or
38  * (at your option) any later version.
39  *
40  * This program is distributed in the hope that it will be useful,
41  * but WITHOUT ANY WARRANTY; without even the implied warranty of
42  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
43  * GNU General Public License for more details.
44  *
45  * You should have received a copy of the GNU General Public License
46  * along with this program; if not, write to the Free Software
47  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
48  */
49 
50 /*
51  * Functions needed for producing a KDE directory hierarchy
52  * configuration
53  *
54  * In this case the rootmenu is the top level directory
55  */
56 
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #include <fcntl.h>
62 #include <unistd.h>
63 #include <dirent.h>
64 #include <errno.h>
65 #include <string.h>
66 #include <ctype.h>
67 #include <pwd.h>
68 #include <strings.h>
69 
70 #include "wmconfig.h"
71 #include "prototypes.h"
72 #include "package.h"
73 
74 #if (defined(__unix__) || defined(unix)) && !defined(USG)
75 #include <limits.h>
76 #include <sys/param.h>
77 #endif
78 
79 #define KDE_DIR		".kde/share/applnk/wmconfig"
80 #define KDE_MENU_ICON	"package.xpm"
81 
82 extern const char *root_menu_name;
83 extern const char *output_directory;
84 extern unsigned int flags;
85 
create_kdelnk(const char * file,struct package * app)86 static void create_kdelnk(const char *file, struct package *app)
87 {
88     int fd;
89     FILE *f;
90 
91     if (app == (struct package *)NULL) {
92 	return;
93     }
94 
95     /* KDE does not like starting things in the background */
96     if (app->exec != NULL) {
97 	char *p;
98 	p = strrchr(app->exec, '&');
99 	if (p != NULL) {
100 	    *p = '\0';
101 	}
102     }
103 
104     /*  At the very least we need a filename and command to execute:  */
105     if (file == NULL || app->exec == NULL || app->restart) {
106 	return;
107     }
108 
109     fd = open(file, O_CREAT | O_EXCL | O_RDWR, 0600);
110     f = fdopen (fd, "wx");
111     if (f == (FILE *) NULL) {
112 	fprintf(stderr, gettext ("Could not create file %s\n"), file);
113 	perror("Error code");
114 	return;
115     }
116 
117     /*  Write the .kdelnk file:  */
118     fprintf(f, "# KDE Config File\n");
119     fprintf(f, "[KDE Desktop Entry]\n");
120     if (app->name != NULL) {
121 	fprintf(f, "Name=%s\n", app->name);
122     }
123     if ((app->icon != NULL) && (!is_set(NO_ICONS))) {
124 	fprintf(f, "Icon=%s\n", app->icon);
125     }
126     if ((app->mini_icon != NULL) && (!is_set(NO_MINI_ICONS))) {
127 	fprintf(f, "MiniIcon=%s\n", app->mini_icon);
128     }
129     if (app->description != NULL) {
130 	fprintf(f, "Comment=%s\n", app->description);
131     }
132     if (app->terminal != NULL) {
133 	fprintf(f, "Terminal=true\n");
134     }
135     fprintf(f, "Exec=%s\n", app->exec);
136     fprintf(f, "Type=Application\n");
137 
138     /* Mimetype Support */
139     if (app->mimetype != NULL) {
140 	fprintf(f, "MimeType=%s;\n", app->mimetype);
141     }
142     fclose(f);
143 }
144 
145 /*  Like mkdir -p  */
make_directory_path(const char * path)146 static void make_directory_path(const char *path)
147 {
148     char buf[PATH_MAX];
149     int pi=0;
150     int bi=0;
151     while( path[pi] != '\0' ) {
152         buf[bi] = path[pi];
153         bi++ ; pi++ ;
154         buf[bi] = '\0';
155         if ( path[pi] == '\0' || path[pi] == '/' ) {
156             mkdir(buf, 0700);
157         }
158     }
159 }
160 
161 
create_kde_menu_directory(const char * directory,const char * name)162 static void create_kde_menu_directory(const char *directory, const char *name)
163 {
164     char dot_directory[PATH_MAX+1];
165     int fd;
166     FILE *f;
167 
168     make_directory_path(directory);
169     snprintf(dot_directory, sizeof(dot_directory), "%s/.directory", directory);
170     fd = open(dot_directory, O_CREAT | O_EXCL | O_RDWR, 0600);
171     f = fdopen (fd, "wx");
172     if (f == (FILE *) NULL) {
173         fprintf(stderr, gettext ("Could not create file %s\n"), dot_directory);
174         perror("Error code");
175         return;
176     }
177     fprintf(f, "# KDE Config File\n");
178     fprintf(f, "[KDE Desktop Entry]\n");
179     fprintf(f, "Icon=%s\n", KDE_MENU_ICON);
180     fprintf(f, "Name=%s\n", name);
181     fclose(f);
182 }
183 
make_dir(struct group * root,int level,const char * dir_name)184 static void make_dir(struct group *root, int level, const char *dir_name)
185 {
186     struct item *item;
187     char c_tmp[PATH_MAX];
188 
189     if (root == (struct group *)NULL) {
190 	return;
191     }
192 
193     item = root->items;
194     while (item->type != 0) {
195 	if (item->type == ITEM_MENU) {
196 	    struct group *tmp;
197 
198 	    tmp = (struct group *)item->data;
199 	    snprintf(c_tmp, sizeof(c_tmp), "%s/%s", single_string(dir_name), single_string(tmp->name) );
200 	    create_kde_menu_directory(c_tmp, tmp->name);
201 	} else if (item->type == ITEM_APP) {
202 	    struct package *app;
203 
204 	    app = (struct package *)item->data;
205 	    if (app->name && app->exec) {
206 		snprintf(c_tmp, sizeof(c_tmp), "%s/%s.kdelnk", single_string(dir_name), single_string(app->name) );
207                 create_kdelnk(c_tmp, app);
208 	    }
209 	}
210 	item++;
211     }
212     /* second pass, recursive output... */
213     item = root->items;
214     while (item->type != 0) {
215 	if (item->type == ITEM_MENU) {
216             struct group *tmp;
217 
218 	    tmp = (struct group *)item->data;
219 	    snprintf(c_tmp, sizeof(c_tmp), "%s/%s", dir_name, tmp->name);
220 	    make_dir(item->data, level+1, c_tmp);
221 	}
222 	item++;
223     }
224 }
225 
clean_dir(const char * dir_name)226 static void clean_dir(const char *dir_name)
227 {
228     struct dirent **namelist;
229     int nr_files;
230     int i;
231 
232     if (dir_name == NULL) {
233 	return;
234     }
235 
236     /* read the whole directory in one pass */
237     nr_files = scandir(dir_name, &namelist, NULL, alphasort);
238     for (i = 0; i < nr_files; i++) {
239 	if ( (strcmp(namelist[i]->d_name, ".") != 0) && (strcmp(namelist[i]->d_name, "..") != 0) ) {
240 	    struct stat st;
241 	    char tmp[PATH_MAX];
242 	    int retval;
243 
244 	    snprintf(tmp, sizeof(tmp), "%s/%s", dir_name, namelist[i]->d_name);
245 	    if (stat(tmp, &st) != 0) {
246 		fprintf(stderr, gettext ("Could not stat %s\n"), tmp);
247 		return;
248 	    }
249 	    if (S_ISDIR(st.st_mode)) {
250 		clean_dir(tmp);
251 		retval = rmdir(tmp);
252 	    } else {
253 		retval = unlink(tmp);
254 	    }
255 	    if (retval != 0) {
256 		perror("Could not remove");
257 		return;
258 	    }
259 	}
260 	free(namelist[i]);
261     }
262 
263     if (nr_files && namelist) {
264 	free(namelist);
265     }
266 }
267 
268 /*
269  * Main function
270  */
output_kde(struct group * root)271 void output_kde(struct group *root)
272 {
273     struct stat st;
274     char root_dir[PATH_MAX];
275     struct passwd *pw = NULL;
276 
277     pw = getpwuid(getuid());
278     if (pw == (struct passwd *)NULL) {
279 	fprintf(stderr, gettext ("Could not find out who you are (getpwnam failed)!\n"));
280 	return;
281     }
282 
283     if (output_directory == NULL) {
284 	snprintf(root_dir, sizeof(root_dir), "%s/%s", pw->pw_dir, KDE_DIR);
285     } else {
286 	snprintf(root_dir, sizeof(root_dir), "%s", output_directory);
287     }
288 
289     /* First, check if the root_dir already exists and remove it */
290     if (stat(root_dir, &st) == 0) {
291 	/* that one exists */
292 	if (!S_ISDIR(st.st_mode)) {
293 	    fprintf(stderr, gettext ("Error: %s exists but it is not a directory\n"), root_dir);
294 	    return;
295 	}
296 	clean_dir(root_dir);
297 	rmdir(root_dir);
298     }
299     create_kde_menu_directory(root_dir, DEFAULT_ROOT_NAME);
300     make_dir(root, 0, root_dir);
301 }
302