09adad203ad92ee958f8611493df4c9a3c430dfd
[pandora-libraries.git] / lib / pnd_discovery.c
1
2 #include <stdio.h> /* for FILE etc */
3 #include <stdlib.h> /* for malloc */
4 #include <string.h> /* for making ftw.h happy */
5
6 #define _XOPEN_SOURCE 500
7 #define __USE_XOPEN_EXTENDED
8 #include <ftw.h> /* for nftw, tree walker */
9
10 #include "pnd_container.h"
11 #include "pnd_pxml.h"
12 #include "pnd_discovery.h"
13 #include "pnd_pathiter.h"
14 #include "pnd_apps.h"
15
16 #warning "PND/PNZ support is not included yet; scripts need writing"
17 #warning "  /usr/pandora/bin/pnd_valid.sh"
18 #warning "  /usr/pandora/bin/pnd_prepare.sh"
19 #warning "  /usr/pandora/bin/pnd_unprepare.sh"
20
21 // need these 'globals' due to the way nftw and ftw work :/
22 static pnd_box_handle disco_box;
23 static char *disco_overrides = NULL;
24
25 void pnd_disco_destroy ( pnd_disco_t *p ) {
26
27   if ( p -> title_en ) {
28     free ( p -> title_en );
29   }
30
31   if ( p -> icon ) {
32     free ( p -> icon );
33   }
34
35   if ( p -> exec ) {
36     free ( p -> exec );
37   }
38
39   if ( p -> unique_id ) {
40     free ( p -> unique_id );
41   }
42
43   if ( p -> main_category ) {
44     free ( p -> main_category );
45   }
46
47   if ( p -> clockspeed ) {
48     free ( p -> clockspeed );
49   }
50
51   return;
52 }
53
54 static int pnd_disco_callback ( const char *fpath, const struct stat *sb,
55                                 int typeflag, struct FTW *ftwbuf )
56 {
57   unsigned char valid = 0; // 1 for plaintext PXML, 2 for PND...
58
59   // PXML.xml is a possible application candidate (and not a dir named PXML.xml :)
60   if ( typeflag & FTW_D ) {
61     return ( 0 ); // skip directories and other non-regular files
62   }
63
64   if ( strcasecmp ( fpath + ftwbuf -> base, PXML_FILENAME ) == 0 ) {
65     valid = 1;
66   }
67
68   // PND file and others may be valid as well .. but lets leave that for now
69   //
70   // PND and PNZ and whatever
71   //
72
73   // if not a file of interest, just keep looking until we run out
74   if ( ! valid ) {
75     return ( 0 );
76   }
77
78   // potentially a valid application
79   if ( valid == 1 ) {
80     // Plaintext PXML file
81     //printf ( "disco callback encountered '%s'\n", fpath );
82
83     pnd_pxml_handle pxmlh;
84
85     // pick up the PXML if we can
86
87     pxmlh = pnd_pxml_fetch ( (char*) fpath );
88
89     if ( ! pxmlh ) {
90       return ( 0 ); // continue the scan
91     }
92
93     // look for any overrides, if requested
94 #warning pnd_pxml_merge_override removed by Cpasjuste ...
95   //  pnd_pxml_merge_override ( pxmlh, disco_overrides );
96
97     // check for validity and add to resultset if it looks executable
98     if ( pnd_is_pxml_valid_app ( pxmlh ) ) {
99       pnd_disco_t *p;
100
101       p = pnd_box_allocinsert ( disco_box, (char*) fpath, sizeof(pnd_disco_t) );
102       p -> title_en = strdup ( pnd_pxml_get_app_name ( pxmlh ) );
103       p -> icon = strdup ( pnd_pxml_get_icon_path ( pxmlh ) );
104       p -> exec = strdup ( pnd_pxml_get_exec_path ( pxmlh ) );
105       p -> unique_id = strdup ( pnd_pxml_get_unique_id ( pxmlh ) );
106       p -> main_category = strdup ( pnd_pxml_get_primary_category ( pxmlh ) );
107       p -> clockspeed = strdup ( pnd_pxml_get_clockspeed ( pxmlh ) ); 
108
109     }
110
111     // ditch pxml
112         pnd_pxml_delete ( pxmlh );
113
114         return 0;
115   } else if ( valid == 2 ) {
116     // PND ... ??
117   }
118
119   return ( 0 ); // continue the tree walk
120 }
121
122 pnd_box_handle pnd_disco_search ( char *searchpath, char *overridespath ) {
123
124   //printf ( "Searchpath to discover: '%s'\n", searchpath );
125
126   // alloc a container for the result set
127   disco_box = pnd_box_new ( "discovery" );
128   disco_overrides = overridespath;
129
130   /* iterate across the paths within the searchpath, attempting to locate applications
131    */
132
133   SEARCHPATH_PRE
134   {
135
136     // invoke the dir walking function; thankfully Linux includes a pretty good one
137     nftw ( buffer,               // path to descend
138            pnd_disco_callback,   // callback to do processing
139            10,                   // no more than X open fd's at once
140            FTW_PHYS );           // do not follow symlinks
141
142   }
143   SEARCHPATH_POST
144
145   // return whatever we found, or NULL if nada
146   if ( ! pnd_box_get_head ( disco_box ) ) {
147     pnd_box_delete ( disco_box );
148     disco_box = NULL;
149   }
150
151   return ( disco_box );
152 }
153
154 unsigned char pnd_emit_dotdesktop ( char *targetpath, pnd_disco_t *p ) {
155   char filename [ FILENAME_MAX ];
156   char buffer [ 1024 ];
157   FILE *f;
158
159   // specification
160   // http://standards.freedesktop.org/desktop-entry-spec
161
162   // validation
163
164   if ( ! p -> unique_id ) {
165     return ( 0 );
166   }
167
168   if ( ! p -> exec ) {
169     return ( 0 );
170   }
171
172   // set up
173
174   sprintf ( filename, "%s/%s.desktop", targetpath, p -> unique_id );
175
176   // emit
177
178   f = fopen ( filename, "w" );
179
180   if ( ! f ) {
181     return ( 0 );
182   }
183
184   if ( p -> title_en ) {
185     snprintf ( buffer, 1020, "Name=%s\n", p -> title_en );
186     fprintf ( f, "%s", buffer );
187   }
188
189   fprintf ( f, "Type=Application\n" );
190   fprintf ( f, "Version=1.0\n" );
191
192   if ( p -> icon ) {
193     snprintf ( buffer, 1020, "Icon=%s\n", p -> icon );
194     fprintf ( f, "%s", buffer );
195   }
196
197   if ( p -> description_en ) {
198     snprintf ( buffer, 1020, "Comment=%s\n", p -> description_en );
199     fprintf ( f, "%s", buffer );
200   }
201
202   if ( p -> startdir ) {
203     snprintf ( buffer, 1020, "Path=%s\n", p -> startdir );
204     fprintf ( f, "%s", buffer );
205   } else {
206     fprintf ( f, "Path=%s\n", PND_DEFAULT_WORKDIR );
207   }
208
209   if ( p -> exec ) {
210     snprintf ( buffer, 1020, "Exec=%s\n", p -> exec );
211     fprintf ( f, "%s", buffer );
212   }
213
214   fclose ( f );
215
216   return ( 1 );
217 }