01f4c9a39ddf5cbcb23069ed33263fb48f5f4632
[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 #include "pnd_pndfiles.h"
16
17 // need these 'globals' due to the way nftw and ftw work :/
18 static pnd_box_handle disco_box;
19 static char *disco_overrides = NULL;
20
21 void pnd_disco_destroy ( pnd_disco_t *p ) {
22
23   if ( p -> title_en ) {
24     free ( p -> title_en );
25   }
26
27   if ( p -> icon ) {
28     free ( p -> icon );
29   }
30
31   if ( p -> exec ) {
32     free ( p -> exec );
33   }
34
35   if ( p -> unique_id ) {
36     free ( p -> unique_id );
37   }
38
39   if ( p -> main_category ) {
40     free ( p -> main_category );
41   }
42
43   if ( p -> clockspeed ) {
44     free ( p -> clockspeed );
45   }
46
47   return;
48 }
49
50 static int pnd_disco_callback ( const char *fpath, const struct stat *sb,
51                                 int typeflag, struct FTW *ftwbuf )
52 {
53   unsigned char valid = 0; // 1 for plaintext PXML, 2 for PND...
54
55   // PXML.xml is a possible application candidate (and not a dir named PXML.xml :)
56   if ( typeflag & FTW_D ) {
57     return ( 0 ); // skip directories and other non-regular files
58   }
59
60   // PND/PNZ file and others may be valid as well .. but lets leave that for now
61   if ( strcasecmp ( fpath + ftwbuf -> base, PXML_FILENAME ) == 0 ) {
62     valid = 1;
63   } else if ( strcasecmp ( fpath + ftwbuf -> base, PND_PACKAGE_FILEEXT "\0" ) == 0 ) {
64     valid = 2;
65   }
66
67   // if not a file of interest, just keep looking until we run out
68   if ( ! valid ) {
69     return ( 0 );
70   }
71
72   // potentially a valid application
73   if ( valid == 1 ) {
74     // Plaintext PXML file
75     //printf ( "disco callback encountered '%s'\n", fpath );
76
77     pnd_pxml_handle pxmlh;
78
79     // pick up the PXML if we can
80
81     pxmlh = pnd_pxml_fetch ( (char*) fpath );
82
83     if ( ! pxmlh ) {
84       return ( 0 ); // continue the scan
85     }
86
87     // look for any overrides, if requested
88     pnd_pxml_merge_override ( pxmlh, disco_overrides );
89
90     // check for validity and add to resultset if it looks executable
91     if ( pnd_is_pxml_valid_app ( pxmlh ) ) {
92       pnd_disco_t *p;
93
94       p = pnd_box_allocinsert ( disco_box, (char*) fpath, sizeof(pnd_disco_t) );
95       p -> title_en = strdup ( pnd_pxml_get_app_name ( pxmlh ) );
96       p -> icon = strdup ( pnd_pxml_get_icon_path ( pxmlh ) );
97       p -> exec = strdup ( pnd_pxml_get_exec_path ( pxmlh ) );
98       p -> unique_id = strdup ( pnd_pxml_get_unique_id ( pxmlh ) );
99       p -> main_category = strdup ( pnd_pxml_get_primary_category ( pxmlh ) );
100       p -> clockspeed = strdup ( pnd_pxml_get_clockspeed ( pxmlh ) ); 
101
102     }
103
104     // ditch pxml
105     pnd_pxml_delete ( pxmlh );
106
107   } else if ( valid == 2 ) {
108     // PND ... ??
109     printf ( "PND: disco callback encountered '%s'\n", fpath );
110
111     // is this a valid .pnd file? The filename is a candidate already, but verify..
112     // .. presence of PXML appeneded, or at least contained within?
113     // .. presence of an icon appended after PXML?
114
115   }
116
117   return ( 0 ); // continue the tree walk
118 }
119
120 pnd_box_handle pnd_disco_search ( char *searchpath, char *overridespath ) {
121
122   //printf ( "Searchpath to discover: '%s'\n", searchpath );
123
124   // alloc a container for the result set
125   disco_box = pnd_box_new ( "discovery" );
126   disco_overrides = overridespath;
127
128   /* iterate across the paths within the searchpath, attempting to locate applications
129    */
130
131   SEARCHPATH_PRE
132   {
133
134     // invoke the dir walking function; thankfully Linux includes a pretty good one
135     nftw ( buffer,               // path to descend
136            pnd_disco_callback,   // callback to do processing
137            10,                   // no more than X open fd's at once
138            FTW_PHYS );           // do not follow symlinks
139
140   }
141   SEARCHPATH_POST
142
143   // return whatever we found, or NULL if nada
144   if ( ! pnd_box_get_head ( disco_box ) ) {
145     pnd_box_delete ( disco_box );
146     disco_box = NULL;
147   }
148
149   return ( disco_box );
150 }
151
152 unsigned char pnd_emit_dotdesktop ( char *targetpath, pnd_disco_t *p ) {
153   char filename [ FILENAME_MAX ];
154   char buffer [ 1024 ];
155   FILE *f;
156
157   // specification
158   // http://standards.freedesktop.org/desktop-entry-spec
159
160   // validation
161
162   if ( ! p -> unique_id ) {
163     return ( 0 );
164   }
165
166   if ( ! p -> exec ) {
167     return ( 0 );
168   }
169
170   // set up
171
172   sprintf ( filename, "%s/%s.desktop", targetpath, p -> unique_id );
173
174   // emit
175
176   //printf ( "EMIT DOTDESKTOP '%s'\n", filename );
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 0
198   if ( p -> description_en ) {
199     snprintf ( buffer, 1020, "Comment=%s\n", p -> description_en );
200     fprintf ( f, "%s", buffer );
201   }
202 #endif
203
204 #if 0
205   if ( p -> startdir ) {
206     snprintf ( buffer, 1020, "Path=%s\n", p -> startdir );
207     fprintf ( f, "%s", buffer );
208   } else {
209     fprintf ( f, "Path=%s\n", PND_DEFAULT_WORKDIR );
210   }
211 #endif
212
213   if ( p -> exec ) {
214     snprintf ( buffer, 1020, "Exec=%s\n", p -> exec );
215     fprintf ( f, "%s", buffer );
216   }
217
218   fprintf ( f, "_Source=libpnd\n" ); // should we need to know 'who' created the file during trimming
219
220   fclose ( f );
221
222   return ( 1 );
223 }