1 /***************************************************************************
2 begin : Thu Apr 03 2003
3 copyright : (C) 2003-2010 by Martin Preuss
4 email : martin@libchipcard.de
5
6 ***************************************************************************
7 * *
8 * This library is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU Lesser General Public *
10 * License as published by the Free Software Foundation; either *
11 * version 2.1 of the License, or (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 * *
23 ***************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28
29 #define DISABLE_DEBUGLOG
30
31
32 #include "plugindescr_p.h"
33 #include "i18n_l.h"
34 #include <gwenhywfar/buffer.h>
35 #include <gwenhywfar/debug.h>
36 #include <gwenhywfar/directory.h>
37 #include <gwenhywfar/i18n.h>
38
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44 #include <errno.h>
45 #include <string.h>
46 #ifdef HAVE_STRINGS_H
47 # include <strings.h>
48 #endif
49
50
51
GWEN_LIST_FUNCTIONS(GWEN_PLUGIN_DESCRIPTION,GWEN_PluginDescription)52 GWEN_LIST_FUNCTIONS(GWEN_PLUGIN_DESCRIPTION, GWEN_PluginDescription)
53 GWEN_LIST2_FUNCTIONS(GWEN_PLUGIN_DESCRIPTION, GWEN_PluginDescription)
54
55
56
57 GWEN_PLUGIN_DESCRIPTION *GWEN_PluginDescription_new(GWEN_XMLNODE *node)
58 {
59 GWEN_PLUGIN_DESCRIPTION *pd;
60 const char *p;
61
62 GWEN_NEW_OBJECT(GWEN_PLUGIN_DESCRIPTION, pd);
63 pd->refCount=1;
64 DBG_MEM_INC("GWEN_PLUGIN_DESCRIPTION", 0);
65 GWEN_LIST_INIT(GWEN_PLUGIN_DESCRIPTION, pd);
66 p=GWEN_XMLNode_GetProperty(node, "name", 0);
67 if (!p) {
68 DBG_ERROR(GWEN_LOGDOMAIN, "Unnamed plugin");
69 GWEN_PluginDescription_free(pd);
70 return 0;
71 }
72 pd->name=strdup(p);
73 pd->xmlNode=GWEN_XMLNode_dup(node);
74
75 p=GWEN_XMLNode_GetProperty(node, "i18n", NULL);
76 if (!p) {
77 DBG_NOTICE(GWEN_LOGDOMAIN, "Plugin has no I18N domain, using GWEN");
78 p="gwenhywfar";
79 }
80 pd->langDomain=strdup(p);
81
82 p=GWEN_XMLNode_GetProperty(node, "type", 0);
83 if (!p) {
84 DBG_ERROR(GWEN_LOGDOMAIN, "Plugin has no type");
85 GWEN_PluginDescription_free(pd);
86 return 0;
87 }
88 pd->type=strdup(p);
89
90 p=GWEN_XMLNode_GetCharValue(node, "version", 0);
91 if (p)
92 pd->version=strdup(p);
93 p=GWEN_XMLNode_GetCharValue(node, "author", 0);
94 if (p)
95 pd->author=strdup(p);
96 p=GWEN_XMLNode_GetCharValue(node, "short", 0);
97 if (p)
98 pd->shortDescr=strdup(p);
99 p=GWEN_XMLNode_GetCharValue(node, "descr", 0);
100 if (p)
101 pd->longDescr=strdup(p);
102 return pd;
103 }
104
105
106
GWEN_PluginDescription_free(GWEN_PLUGIN_DESCRIPTION * pd)107 void GWEN_PluginDescription_free(GWEN_PLUGIN_DESCRIPTION *pd)
108 {
109 if (pd) {
110 assert(pd->refCount);
111 if (pd->refCount==1) {
112 DBG_MEM_DEC("GWEN_PLUGIN_DESCRIPTION");
113 GWEN_LIST_FINI(GWEN_PLUGIN_DESCRIPTION, pd);
114 free(pd->path);
115 GWEN_XMLNode_free(pd->xmlNode);
116 free(pd->fileName);
117 free(pd->longDescr);
118 free(pd->shortDescr);
119 free(pd->author);
120 free(pd->version);
121 free(pd->langDomain);
122 free(pd->type);
123 free(pd->name);
124 pd->refCount=0;
125 GWEN_FREE_OBJECT(pd);
126 }
127 else
128 pd->refCount--;
129 }
130 }
131
132
133
GWEN_PluginDescription_Attach(GWEN_PLUGIN_DESCRIPTION * pd)134 void GWEN_PluginDescription_Attach(GWEN_PLUGIN_DESCRIPTION *pd)
135 {
136 assert(pd);
137 assert(pd->refCount);
138 pd->refCount++;
139 }
140
141
142
GWEN_PluginDescription_dup(const GWEN_PLUGIN_DESCRIPTION * pd)143 GWEN_PLUGIN_DESCRIPTION *GWEN_PluginDescription_dup(const GWEN_PLUGIN_DESCRIPTION *pd)
144 {
145 GWEN_PLUGIN_DESCRIPTION *np;
146 const char *s;
147
148 assert(pd);
149 GWEN_NEW_OBJECT(GWEN_PLUGIN_DESCRIPTION, np);
150 np->refCount=1;
151 DBG_MEM_INC("GWEN_PLUGIN_DESCRIPTION", 0);
152 GWEN_LIST_INIT(GWEN_PLUGIN_DESCRIPTION, np);
153
154 s=pd->fileName;
155 if (s)
156 np->fileName=strdup(s);
157
158 s=pd->path;
159 if (s)
160 np->path=strdup(s);
161 s=pd->name;
162 if (s)
163 np->name=strdup(s);
164 s=pd->type;
165 if (s)
166 np->type=strdup(s);
167 s=pd->langDomain;
168 if (s)
169 np->langDomain=strdup(s);
170 s=pd->shortDescr;
171 if (s)
172 np->shortDescr=strdup(s);
173 s=pd->author;
174 if (s)
175 np->author=strdup(s);
176 s=pd->version;
177 if (s)
178 np->version=strdup(s);
179 s=pd->longDescr;
180 if (s)
181 np->longDescr=strdup(s);
182 np->isActive=pd->isActive;
183 if (pd->xmlNode)
184 np->xmlNode=GWEN_XMLNode_dup(pd->xmlNode);
185
186 return np;
187 }
188
189
190
GWEN_PluginDescription_List2_freeAll_cb(GWEN_PLUGIN_DESCRIPTION * pd,void * user_data)191 GWEN_PLUGIN_DESCRIPTION *GWEN_PluginDescription_List2_freeAll_cb(GWEN_PLUGIN_DESCRIPTION *pd,
192 __attribute__((unused)) void *user_data)
193 {
194 GWEN_PluginDescription_free(pd);
195 return 0;
196 }
197
198
199
GWEN_PluginDescription_List2_freeAll(GWEN_PLUGIN_DESCRIPTION_LIST2 * pdl)200 void GWEN_PluginDescription_List2_freeAll(GWEN_PLUGIN_DESCRIPTION_LIST2 *pdl)
201 {
202 GWEN_PluginDescription_List2_ForEach
203 (pdl,
204 GWEN_PluginDescription_List2_freeAll_cb,
205 0);
206 GWEN_PluginDescription_List2_free(pdl);
207 }
208
209
210
GWEN_PluginDescription_GetPath(const GWEN_PLUGIN_DESCRIPTION * pd)211 const char *GWEN_PluginDescription_GetPath(const GWEN_PLUGIN_DESCRIPTION *pd)
212 {
213 assert(pd);
214 return pd->path;
215 }
216
217
218
GWEN_PluginDescription_SetPath(GWEN_PLUGIN_DESCRIPTION * pd,const char * s)219 void GWEN_PluginDescription_SetPath(GWEN_PLUGIN_DESCRIPTION *pd,
220 const char *s)
221 {
222 assert(pd);
223 free(pd->path);
224 if (s)
225 pd->path=strdup(s);
226 else
227 pd->path=0;
228 }
229
230
231
GWEN_PluginDescription_GetName(const GWEN_PLUGIN_DESCRIPTION * pd)232 const char *GWEN_PluginDescription_GetName(const GWEN_PLUGIN_DESCRIPTION *pd)
233 {
234 assert(pd);
235 return pd->name;
236 }
237
238
239
GWEN_PluginDescription_GetType(const GWEN_PLUGIN_DESCRIPTION * pd)240 const char *GWEN_PluginDescription_GetType(const GWEN_PLUGIN_DESCRIPTION *pd)
241 {
242 assert(pd);
243 return pd->type;
244 }
245
246
247
GWEN_PluginDescription_GetShortDescr(const GWEN_PLUGIN_DESCRIPTION * pd)248 const char *GWEN_PluginDescription_GetShortDescr(const GWEN_PLUGIN_DESCRIPTION *pd)
249 {
250 assert(pd);
251 return GWEN_I18N_Translate(pd->langDomain, pd->shortDescr);
252 }
253
254
255
GWEN_PluginDescription_GetAuthor(const GWEN_PLUGIN_DESCRIPTION * pd)256 const char *GWEN_PluginDescription_GetAuthor(const GWEN_PLUGIN_DESCRIPTION *pd)
257 {
258 assert(pd);
259 return pd->author;
260 }
261
262
263
GWEN_PluginDescription_GetVersion(const GWEN_PLUGIN_DESCRIPTION * pd)264 const char *GWEN_PluginDescription_GetVersion(const GWEN_PLUGIN_DESCRIPTION *pd)
265 {
266 assert(pd);
267 return pd->version;
268 }
269
270
271
GWEN_PluginDescription_GetLongDescr(const GWEN_PLUGIN_DESCRIPTION * pd)272 const char *GWEN_PluginDescription_GetLongDescr(const GWEN_PLUGIN_DESCRIPTION *pd)
273 {
274 assert(pd);
275 return GWEN_I18N_Translate(pd->langDomain, pd->longDescr);
276 }
277
278
279
GWEN_PluginDescription__GetLongDescrByFormat(const GWEN_PLUGIN_DESCRIPTION * pd,const char * s,GWEN_BUFFER * buf)280 int GWEN_PluginDescription__GetLongDescrByFormat(const GWEN_PLUGIN_DESCRIPTION *pd,
281 const char *s,
282 GWEN_BUFFER *buf)
283 {
284 GWEN_XMLNODE *n;
285
286 assert(pd);
287 assert(pd->xmlNode);
288
289 n=GWEN_XMLNode_FindFirstTag(pd->xmlNode, "descr", 0, 0);
290 if (n) {
291 n=GWEN_XMLNode_FindFirstTag(n, "text", "format", s);
292 while (n) {
293 if (0==GWEN_XMLNode_GetProperty(n, "lang", 0)) {
294 int rv;
295
296 rv=GWEN_XMLNode_toBuffer(n, buf, GWEN_XML_FLAGS_TOLERANT_ENDTAGS);
297 if (rv) {
298 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
299 return rv;
300 }
301 return 0;
302 }
303 n=GWEN_XMLNode_FindNextTag(n, "text", "format", s);
304 } /* while */
305 }
306
307 return -1;
308 }
309
310
311
GWEN_PluginDescription__GetLocalizedLongDescrByFormat(const GWEN_PLUGIN_DESCRIPTION * pd,const char * s,const char * lang,GWEN_BUFFER * buf)312 int GWEN_PluginDescription__GetLocalizedLongDescrByFormat(const GWEN_PLUGIN_DESCRIPTION *pd,
313 const char *s,
314 const char *lang,
315 GWEN_BUFFER *buf)
316 {
317 GWEN_XMLNODE *n;
318
319 assert(pd);
320 assert(pd->xmlNode);
321
322 n=GWEN_XMLNode_FindFirstTag(pd->xmlNode, "descr", 0, 0);
323 if (n) {
324 n=GWEN_XMLNode_FindFirstTag(n, "text", "lang", lang);
325 while (n) {
326 const char *fmt;
327
328 fmt=GWEN_XMLNode_GetProperty(n, "format", 0);
329 if (fmt && strcasecmp(fmt, s)==0) {
330 int rv;
331
332 rv=GWEN_XMLNode_toBuffer(n, buf, GWEN_XML_FLAGS_TOLERANT_ENDTAGS);
333 if (rv) {
334 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
335 return rv;
336 }
337 return 0;
338 }
339 n=GWEN_XMLNode_FindNextTag(n, "text", "lang", lang);
340 } /* while */
341 }
342
343 return -1;
344 }
345
346
347
348 #ifndef NO_DEPRECATED_SYMBOLS
GWEN_PluginDescription_GetLongDescrByFormat(const GWEN_PLUGIN_DESCRIPTION * pd,const char * s,GWEN_BUFFER * buf)349 int GWEN_PluginDescription_GetLongDescrByFormat(const GWEN_PLUGIN_DESCRIPTION *pd,
350 const char *s,
351 GWEN_BUFFER *buf)
352 {
353 GWEN_STRINGLIST *langl;
354 int rv;
355
356 langl=GWEN_I18N_GetCurrentLocaleList();
357 if (langl) {
358 GWEN_STRINGLISTENTRY *se;
359
360 se=GWEN_StringList_FirstEntry(langl);
361 while (se) {
362 const char *l;
363
364 l=GWEN_StringListEntry_Data(se);
365 DBG_NOTICE(GWEN_LOGDOMAIN, "Trying locale \"%s\"", l);
366 assert(l);
367
368 rv=GWEN_PluginDescription__GetLocalizedLongDescrByFormat(pd,
369 s,
370 l,
371 buf);
372 if (rv==0)
373 return rv;
374
375 se=GWEN_StringListEntry_Next(se);
376 } /* while */
377 } /* if language list available */
378
379 /* no localized version found, return text for default language */
380 rv=GWEN_PluginDescription__GetLongDescrByFormat(pd, s, buf);
381 if (rv) {
382 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
383 return rv;
384 }
385
386 return 0;
387 }
388 #endif // ifndef NO_DEPRECATED_SYMBOLS
389
390
GWEN_PluginDescription_GetFileName(const GWEN_PLUGIN_DESCRIPTION * pd)391 const char *GWEN_PluginDescription_GetFileName(const GWEN_PLUGIN_DESCRIPTION *pd)
392 {
393 assert(pd);
394 return pd->fileName;
395 }
396
397
398
GWEN_PluginDescription_SetFileName(GWEN_PLUGIN_DESCRIPTION * pd,const char * s)399 void GWEN_PluginDescription_SetFileName(GWEN_PLUGIN_DESCRIPTION *pd,
400 const char *s)
401 {
402 assert(pd);
403 free(pd->fileName);
404 if (s)
405 pd->fileName=strdup(s);
406 else
407 pd->fileName=0;
408 }
409
410
411
GWEN_PluginDescription_GetXmlNode(const GWEN_PLUGIN_DESCRIPTION * pd)412 GWEN_XMLNODE *GWEN_PluginDescription_GetXmlNode(const GWEN_PLUGIN_DESCRIPTION *pd)
413 {
414 assert(pd);
415 return pd->xmlNode;
416 }
417
418
419
GWEN_LoadPluginDescrs(const char * path)420 GWEN_PLUGIN_DESCRIPTION_LIST2 *GWEN_LoadPluginDescrs(const char *path)
421 {
422 GWEN_PLUGIN_DESCRIPTION_LIST2 *pl;
423
424 pl=GWEN_PluginDescription_List2_new();
425
426 GWEN_LoadPluginDescrsByType(path, 0, pl);
427 if (GWEN_PluginDescription_List2_GetSize(pl)==0) {
428 GWEN_PluginDescription_List2_free(pl);
429 return 0;
430 }
431 return pl;
432 }
433
434
435
GWEN_PluginDescription_IsActive(const GWEN_PLUGIN_DESCRIPTION * pd)436 int GWEN_PluginDescription_IsActive(const GWEN_PLUGIN_DESCRIPTION *pd)
437 {
438 assert(pd);
439 return pd->isActive;
440 }
441
442
443
GWEN_PluginDescription_SetIsActive(GWEN_PLUGIN_DESCRIPTION * pd,int i)444 void GWEN_PluginDescription_SetIsActive(GWEN_PLUGIN_DESCRIPTION *pd, int i)
445 {
446 assert(pd);
447 pd->isActive=i;
448 }
449
450
451
GWEN_LoadPluginDescrsByType(const char * path,const char * type,GWEN_PLUGIN_DESCRIPTION_LIST2 * pdl)452 int GWEN_LoadPluginDescrsByType(const char *path,
453 const char *type,
454 GWEN_PLUGIN_DESCRIPTION_LIST2 *pdl)
455 {
456 GWEN_DIRECTORY *d;
457 GWEN_BUFFER *nbuf;
458 char nbuffer[64];
459 unsigned int pathLen;
460
461 if (!path)
462 path="";
463
464 /* create path */
465 nbuf=GWEN_Buffer_new(0, 256, 0, 1);
466 GWEN_Buffer_AppendString(nbuf, path);
467 pathLen=GWEN_Buffer_GetUsedBytes(nbuf);
468
469 d=GWEN_Directory_new();
470 if (GWEN_Directory_Open(d, GWEN_Buffer_GetStart(nbuf))) {
471 DBG_INFO(GWEN_LOGDOMAIN,
472 "Path \"%s\" is not available",
473 GWEN_Buffer_GetStart(nbuf));
474 GWEN_Buffer_free(nbuf);
475 GWEN_Directory_free(d);
476 return -1;
477 }
478
479 while (!GWEN_Directory_Read(d,
480 nbuffer,
481 sizeof(nbuffer))) {
482 if (strcmp(nbuffer, ".") &&
483 strcmp(nbuffer, "..")) {
484 int nlen;
485
486 nlen=strlen(nbuffer);
487 if (nlen>3) {
488 if (strcasecmp(nbuffer+nlen-4, ".xml")==0) {
489 struct stat st;
490
491 GWEN_Buffer_Crop(nbuf, 0, pathLen);
492 GWEN_Buffer_SetPos(nbuf, pathLen);
493 GWEN_Buffer_AppendByte(nbuf, GWEN_DIR_SEPARATOR);
494 GWEN_Buffer_AppendString(nbuf, nbuffer);
495
496 if (stat(GWEN_Buffer_GetStart(nbuf), &st)) {
497 DBG_ERROR(GWEN_LOGDOMAIN, "stat(%s): %s",
498 GWEN_Buffer_GetStart(nbuf),
499 strerror(errno));
500 }
501 else {
502 if (!S_ISDIR(st.st_mode)) {
503 GWEN_XMLNODE *fileNode;
504
505 fileNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "root");
506 if (GWEN_XML_ReadFile(fileNode,
507 GWEN_Buffer_GetStart(nbuf),
508 GWEN_XML_FLAGS_DEFAULT |
509 GWEN_XML_FLAGS_HANDLE_HEADERS |
510 GWEN_XML_FLAGS_HANDLE_OPEN_HTMLTAGS)) {
511 DBG_WARN(GWEN_LOGDOMAIN,
512 "Bad file \"%s\"", GWEN_Buffer_GetStart(nbuf));
513 }
514 else {
515 GWEN_XMLNODE *node;
516 GWEN_XMLNODE *n;
517 GWEN_STRINGLIST *langl;
518
519 n=0;
520 node=GWEN_XMLNode_FindFirstTag(fileNode, "PluginDescr", 0, 0);
521 if (!node)
522 node=fileNode;
523 langl=GWEN_I18N_GetCurrentLocaleList();
524 if (langl) {
525 GWEN_STRINGLISTENTRY *se;
526
527 se=GWEN_StringList_FirstEntry(langl);
528 while (se) {
529 const char *l;
530
531 l=GWEN_StringListEntry_Data(se);
532 DBG_DEBUG(GWEN_LOGDOMAIN, "Trying locale \"%s\"", l);
533 assert(l);
534 n=GWEN_XMLNode_FindFirstTag(node, "plugin", "lang", l);
535 if (n)
536 break;
537 se=GWEN_StringListEntry_Next(se);
538 } /* while */
539 } /* if language list available */
540
541 if (!n)
542 n=GWEN_XMLNode_FindFirstTag(node, "plugin", 0, 0);
543 if (n) {
544 GWEN_PLUGIN_DESCRIPTION *pd;
545 int loadIt;
546
547 loadIt=1;
548 if (type) {
549 const char *ft;
550
551 ft=GWEN_XMLNode_GetProperty(n, "type", 0);
552 if (!ft)
553 loadIt=0;
554 else if (strcasecmp(ft, type)!=0) {
555 loadIt=0;
556 }
557 } /* if type specified */
558 if (loadIt) {
559 pd=GWEN_PluginDescription_new(n);
560 if (!pd) {
561 DBG_WARN(GWEN_LOGDOMAIN, "Bad plugin description");
562 }
563 else {
564 GWEN_PluginDescription_SetFileName
565 (pd, GWEN_Buffer_GetStart(nbuf));
566 GWEN_Buffer_Crop(nbuf, 0, pathLen);
567 GWEN_Buffer_SetPos(nbuf, pathLen);
568 GWEN_PluginDescription_SetPath
569 (pd, GWEN_Buffer_GetStart(nbuf));
570 GWEN_PluginDescription_List2_PushBack(pdl, pd);
571 }
572 } /* if loadIt */
573 else {
574 DBG_INFO(GWEN_LOGDOMAIN,
575 "Ignoring file \"%s\" (bad/missing type)",
576 GWEN_Buffer_GetStart(nbuf));
577 }
578 }
579 else {
580 DBG_WARN(GWEN_LOGDOMAIN,
581 "File \"%s\" does not contain a plugin "
582 "description",
583 GWEN_Buffer_GetStart(nbuf));
584 }
585 }
586 GWEN_XMLNode_free(fileNode);
587 } /* if !dir */
588 } /* if stat was ok */
589 } /* if XML */
590 } /* if name has more than 3 chars */
591 } /* if not "." and not ".." */
592 } /* while */
593 GWEN_Directory_Close(d);
594 GWEN_Directory_free(d);
595 GWEN_Buffer_free(nbuf);
596
597 return 0;
598 }
599
600
601
602
603
604
605
606
607
608
609
610
611