Change to the linux kernel coding style
[wmaker-crm.git] / src / menureader.c
1 /* menureader.c- root menu definition readers
2  *
3  *  Window Maker window manager
4  *
5  *  Copyright (c) 2000-2003 Alfredo K. Kojima
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20  *  USA.
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28
29 #include "WindowMaker.h"
30
31 #include "misc.h"
32
33 #include "rootmenu.h"
34
35 typedef struct PLMenuReaderData {
36         WRootMenuReader *reader;
37
38         WMPropList *pl;
39         int curIndex;
40
41         WMPropList **submenu;
42         int *curSubIndex;
43         int submenuDepth;
44
45 } PLMenuReaderData;
46
47 typedef struct TextMenuReaderData {
48         WRootMenuReader *reader;
49
50         FILE *file;
51
52 } TextMenuReaderData;
53
54 typedef struct PipeMenuReaderData {
55         WRootMenuReader *reader;
56
57 } PipeMenuReaderData;
58
59 typedef struct DirMenuReaderData {
60         WRootMenuReader *reader;
61
62         char **dirList;
63         int dirCount;
64
65 } DirMenuReaderData;
66
67 /*
68  typedef struct GNOMEMenuReaderData {
69  } GNOMEMenuReaderData;
70  */
71
72 static WRootMenuData *pl_openMenu(WMPropList * pl);
73 static Bool pl_hasMoreData(WRootMenuData * data);
74 static Bool pl_nextCommand(WRootMenuData * data, char **title, char **command, char **parameter, char **shortcut);
75 static void pl_closeMenuFile(WRootMenuData * data);
76
77 static WRootMenuData *text_openMenuFile(char *path);
78 static Bool text_hasMoreData(WRootMenuData * data);
79 static Bool text_nextCommand(WRootMenuData * data,
80                              char **title, char **command, char **parameter, char **shortcut);
81 static void text_closeMenuFile(WRootMenuData * data);
82
83 static WRootMenuData *dir_openMenuFile(char *path);
84 static Bool dir_hasMoreData(WRootMenuData * data);
85 static Bool dir_nextCommand(WRootMenuData * data, char **title, char **command, char **parameter, char **shortcut);
86 static void dir_closeMenuFile(WRootMenuData * data);
87
88 static WRootMenuReader PLMenuReader = {
89         pl_hasMoreData,
90         pl_nextCommand,
91         pl_closeMenuFile
92 };
93
94 static WRootMenuReader TextMenuReader = {
95         text_hasMoreData,
96         text_nextCommand,
97         text_closeMenuFile
98 };
99
100 static WRootMenuReader DirMenuReaderData = {
101         dir_hasMoreData,
102         dir_nextCommand,
103         dir_closeMenuFile
104 };
105
106 /*
107  WRootMenuReader GNOMEMenuReaderData = {
108  };
109  */
110
111 #define LINESIZE 1024
112
113 static char linebuf[LINESIZE];
114
115 /* ---------- proplist ---------- */
116
117 static WRootMenuData *pl_openMenuFile(WMPropList * pl)
118 {
119         PLRootMenuData *data = wmalloc(sizeof(PLRootMenuData));
120
121         data->reader = PLMenuReader;
122
123         data->pl = pl;
124         data->curIndex = 0;
125
126         data->submenu = NULL;
127         data->curSubIndex = NULL;
128         data->submenuDepth = 0;
129
130         return data;
131 }
132
133 static Bool pl_hasMoreData(WRootMenuData * data)
134 {
135 }
136
137 static Bool pl_nextCommand(WRootMenuData * data, char **title, char **command, char **parameter, char **shortcut)
138 {
139 }
140
141 static void pl_closeMenuFile(WRootMenuData * data)
142 {
143         if (data->submenu)
144                 wfree(data->submenu);
145         if (data->curSubIndex)
146                 wfree(data->curSubIndex);
147
148         WMReleasePropList(data->pl);
149
150         wfree(data);
151 }
152
153 /* ---------- text ---------- */
154
155 static WRootMenuData *text_openMenuFile(char *path)
156 {
157         TextMenuReaderData *data;
158
159         data = wmalloc(sizeof(TextMenuReaderData));
160         data->reader = TextMenuReader;
161
162         data->file = fopen(path, "rb");
163         if (!data->file) {
164
165                 return NULL;
166         }
167 }
168
169 static Bool text_hasMoreData(WRootMenuData * data)
170 {
171 }
172
173 static Bool text_nextCommand(WRootMenuData * data, char **title, char **command, char **parameter, char **shortcut)
174 {
175 }
176
177 static void text_closeMenuFile(WRootMenuData * data)
178 {
179 }
180
181 /* ---------- directory ---------- */
182
183 static WRootMenuData *dir_openMenuFile(char *paths, time_t * timestamp)
184 {
185         DirMenuReaderData *data;
186         char **dirs;
187         int dirN;
188         time_t checksum = 0;
189         int i, c;
190
191         /* timestamp for directory is a "checksum" of the directory times */
192
193         wtokensplit(paths, &dirs, &dirN);
194
195         if (dirN == 0) {
196                 return NULL;
197         }
198
199         for (c = 0, i = 0; i < dirN; i++) {
200                 char *tmp;
201
202                 if (strcmp(dirs[i], "-noext") == 0) {
203                         i++;
204                         continue;
205                 }
206
207                 tmp = wexpandpath(dirs[i]);
208                 wfree(dirs[i]);
209                 dirs[i] = tmp;
210
211                 if (stat(dirs[i], &stat_buf) < 0) {
212                         wsyserror(_("%s:could not stat menu"), dirs[i]);
213                         wfree(dirs[i]);
214                         dirs[i] = NULL;
215                 } else {
216                         c++;
217                         checksum += stat_buf.st_mtime;
218                 }
219         }
220
221         if (*timestamp == checksum && *timestamp != 0) {
222                 return NULL;
223         }
224
225         if (c == 0) {
226                 for (i = 0; i < dirN; i++) {
227                         if (dirs[i])
228                                 wfree(dirs[i]);
229                 }
230                 wfree(dirs);
231
232                 return NULL;
233         }
234
235         data = wmalloc(sizeof(DirMenuReaderData));
236         data->reader = DirMenuReader;
237
238 }
239
240 static Bool dir_hasMoreData(WRootMenuData * data)
241 {
242 }
243
244 static Bool dir_nextCommand(WRootMenuData * data, char **title, char **command, char **parameter, char **shortcut)
245 {
246 }
247
248 static void dir_closeMenuFile(WRootMenuData * data)
249 {
250 }
251
252 WRootMenuData *OpenMenu(char *path, time_t * menuTime)
253 {
254         proplist pl;
255         struct stat stat_buf;
256         WRootMenuData *data;
257
258         /* check whether it's a piped menu */
259         if (*path == '|') {
260                 /* piped menus have the following semantics for menuTime:
261                  * if it's 0, then it wasnt loaded yet
262                  * if it's 1, it was already loaded, so do not reload
263                  *      (would be too slow)
264                  * now, menuTime will only be set to 1 if the pipe command is
265                  *      specified as ||command instead of |command
266                  * in other words ||command means force the submenu to always refresh
267                  */
268                 if (*menuTime == 0) {
269                         data = pipe_openMenu(path);
270                 }
271                 if (path[1] != '|') {
272                         *menuTime = 1;
273                 }
274                 return data;
275         }
276
277         if (stat(path, &stat_buf) < 0) {
278                 wsyserror(_("could not stat() menu file '%s'"));
279                 return NULL;
280         }
281
282         /* check whether it's a directory */
283         if (S_ISDIR(stat_buf.st_mode)) {
284                 return dir_openMenuFile(path, menuTime);
285         }
286
287         if (*menuTime >= stat_buf.st_mtime && *menuTime != 0) {
288                 /* no changes in the menu file */
289                 return NULL;
290         }
291
292         /* then check whether it's a proplist menu */
293         pl = WMReadPropListFromFile(path);
294         if (pl && WMIsPLArray(pl)) {
295                 *menuTime = stat_buf.st_mtime;
296                 return pl_openMenu(pl);
297         }
298
299         *menuTime = stat_buf.st_mtime;
300         /* assume its a plain text menu */
301         return text_openMenuFile(path);
302 }
303
304 WRootMenuData *ReopenRootMenu(time_t * checkTime, char **menuPath, time_t * menuTimestamp)
305 {
306         proplist pl;
307         struct stat stat_buf;
308         char *path;
309
310         if (stat(path, &stat_buf) < 0) {
311                 wsyserror(_("could not stat() menu file '%s'"));
312                 return NULL;
313         }
314
315         if (*menuTime >= stat_buf.st_mtime && *checkTime != 0) {
316                 /* no changes in WMRootMenu, see if the contents changed */
317                 if (*menuPath != NULL) {
318                         return OpenMenu(*menuPath, menuTimestamp);
319                 } else {
320                         return NULL;
321                 }
322         }
323
324         *checkTime = stat_buf.st_mtime;
325
326         pl = WMReadPropListFromFile(path);
327         if (!pl) {
328                 wwarning(_("could not load domain %s from user defaults database"), "WMRootMenu");
329                 return NULL;
330         }
331
332         if (WMIsPLString(pl)) {
333                 char *tmp;
334                 char *path;
335                 Bool menu_is_default = False;
336
337                 tmp = wexpandpath(WMGetFromPLString(pl));
338
339                 path = getLocalizedMenuFile(tmp);
340
341                 if (!path) {
342                         path = wfindfile(DEF_CONFIG_PATHS, tmp);
343                 }
344
345                 if (!path) {
346                         wwarning(_("could not find menu file '%s' referenced in WMRootMenu"), tmp);
347                         path = wfindfile(DEF_CONFIG_PATHS, DEF_MENU_FILE);
348                         menu_is_default = True;
349                 }
350
351                 if (!path) {
352                         wwarning(_("could not find any usable menu files. Please check '%s'"), tmp);
353                         wfree(tmp);
354                         return NULL;
355                 }
356
357                 wfree(tmp);
358
359                 if (*menuPath) {
360                         if (strcmp(*menuPath, path) != 0) {
361                                 *menuTimestamp = 0;
362                                 wfree(*menuPath);
363                                 *menuPath = path;
364
365                                 if (menu_is_default) {
366                                         wwarning(_
367                                                  ("using default menu file \"%s\" as the menu referenced in WMRootMenu could not be found "),
368                                                  path);
369                                 }
370                         } else {
371                                 /* the menu path didn't change, but the
372                                  * pointed file might have changed, so we don't return
373                                  */
374                         }
375                 } else {
376                         *menuPath = path;
377                 }
378
379                 return OpenMenu(*menuPath, menuTimestamp);
380         } else if (WMIsPLArray(pl)) {
381
382                 *menuTimestamp = stat_buf.st_mtime;
383
384                 return pl_openMenu(pl);
385         } else {
386                 wwarning(_
387                          ("invalid content in menu file '%s'.\nIt should either be a property list menu or the path to the file, enclosed in \"."),
388                          path);
389                 return NULL;
390         }
391 }