ICONTHEME: add a way to store a selected icontheme in the users preferences.
[citadel] / webcit / icontheme.c
1 /*
2  * Displays and customizes the iconbar.
3  *
4  * Copyright (c) 1996-2012 by the citadel.org team
5  *
6  * This program is open source software.  You can redistribute it and/or
7  * modify it under the terms of the GNU General Public License, version 3.
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
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <dirent.h>
18 #include <errno.h>
19
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <stddef.h>
24
25 #include "webcit.h"
26 #include "webserver.h"
27
28 HashList *AvailableThemes = NULL;
29
30 const StrBuf *DefaultTheme = NULL;
31 void LoadIconthemeSettings(StrBuf *icontheme, long lvalue)
32 {
33         wcsession *WCC = WC;
34         void *vTheme;
35         const StrBuf *theme;
36
37         if (GetHash(AvailableThemes, SKEY(icontheme), &vTheme))
38                 theme = (StrBuf*)vTheme;
39         else
40                 theme = DefaultTheme;
41
42         if (WCC->IconTheme != NULL) 
43                 StrBufPlain(WCC->IconTheme, SKEY(theme));
44         else
45                 WCC->IconTheme = NewStrBufDup(theme);
46 }
47
48
49 void tmplput_icontheme(StrBuf *Target, WCTemplputParams *TP)
50 {
51         wcsession *WCC = WC;
52         if ( (WCC != NULL)     &&
53              (WCC->IconTheme != NULL))
54         {
55                  StrBufAppendTemplate(Target, TP, WCC->IconTheme, 0);
56         }
57         else
58         {
59                  StrBufAppendTemplate(Target, TP, DefaultTheme, 0);
60         }
61 }
62
63
64 int LoadThemeDir(const char *DirName)
65 {
66         StrBuf *Dir = NULL;
67         DIR *filedir = NULL;
68         struct dirent *d;
69         struct dirent *filedir_entry;
70         int d_type = 0;
71         int d_namelen;
72                 
73         filedir = opendir (DirName);
74         if (filedir == NULL) {
75                 return 0;
76         }
77
78         d = (struct dirent *)malloc(offsetof(struct dirent, d_name) + PATH_MAX + 1);
79         if (d == NULL) {
80                 return 0;
81         }
82
83         while ((readdir_r(filedir, d, &filedir_entry) == 0) &&
84                (filedir_entry != NULL))
85         {
86 #ifdef _DIRENT_HAVE_D_NAMELEN
87                 d_namelen = filedir_entry->d_namelen;
88                 d_type = filedir_entry->d_type;
89 #else
90
91 #ifndef DT_UNKNOWN
92 #define DT_UNKNOWN     0
93 #define DT_DIR         4
94 #define DT_REG         8
95 #define DT_LNK         10
96
97 #define IFTODT(mode)   (((mode) & 0170000) >> 12)
98 #define DTTOIF(dirtype)        ((dirtype) << 12)
99 #endif
100                 d_namelen = strlen(filedir_entry->d_name);
101                 d_type = DT_UNKNOWN;
102 #endif
103                 if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~')
104                         continue; /* Ignore backup files... */
105
106                 if ((d_namelen == 1) && 
107                     (filedir_entry->d_name[0] == '.'))
108                         continue;
109
110                 if ((d_namelen == 2) && 
111                     (filedir_entry->d_name[0] == '.') &&
112                     (filedir_entry->d_name[1] == '.'))
113                         continue;
114
115                 if (d_type == DT_UNKNOWN) {
116                         struct stat s;
117                         char path[PATH_MAX];
118                         snprintf(path, PATH_MAX, "%s/%s", 
119                                 DirName, filedir_entry->d_name);
120                         if (stat(path, &s) == 0) {
121                                 d_type = IFTODT(s.st_mode);
122                         }
123                 }
124
125                 switch (d_type)
126                 {
127                 case DT_LNK: /* TODO: check whether its a file or a directory */
128                 case DT_DIR:
129                         /* Skip directories we are not interested in... */
130                         if ((strcmp(filedir_entry->d_name, ".svn") == 0) ||
131                             (strcmp(filedir_entry->d_name, "t") == 0))
132                                 break;
133                         
134                         Dir = NewStrBufPlain (filedir_entry->d_name, d_namelen);
135                         if (DefaultTheme == NULL)
136                                 DefaultTheme = Dir;
137                         Put(AvailableThemes, SKEY(Dir), Dir, HFreeStrBuf);
138                         break;
139                 case DT_REG:
140                 default:
141                         break;
142                 }
143
144
145         }
146         free(d);
147         closedir(filedir);
148
149         return 1;
150 }
151
152 HashList *GetValidThemeHash(StrBuf *Target, WCTemplputParams *TP)
153 {
154         return AvailableThemes;
155 }
156 void 
157 ServerStartModule_ICONTHEME
158 (void)
159 {
160         AvailableThemes = NewHash(1, NULL);
161 }
162 void 
163 InitModule_ICONTHEME
164 (void)
165 {
166         StrBuf *Themes = NewStrBufPlain(static_dirs[0], -1);
167
168         StrBufAppendBufPlain(Themes, HKEY("/"), 0);
169         StrBufAppendBufPlain(Themes, HKEY("webcit_icons"), 0);
170         LoadThemeDir(ChrPtr(Themes));
171         FreeStrBuf(&Themes);
172
173         RegisterPreference("icontheme", _("Icon Theme"), PRF_STRING, LoadIconthemeSettings);
174         RegisterNamespace("ICONTHEME", 0, 0, tmplput_icontheme, NULL, CTX_NONE);
175
176         RegisterIterator("PREF:VALID:THEME", 0, NULL, 
177                          GetValidThemeHash, NULL, NULL, CTX_STRBUF, CTX_NONE, IT_NOFLAG);
178 }
179
180 void 
181 ServerShutdownModule_ICONTHEME
182 (void)
183 {
184         DeleteHash(&AvailableThemes);
185 }
186
187 void 
188 SessionDestroyModule_ICONTHEME
189 (wcsession *sess)
190 {
191         FreeStrBuf(&sess->IconTheme);
192 }
193