mmenu; nearly done support for custom categories; not quite done, but nearly.
[pandora-libraries.git] / minimenu / mmcustom_cats.c
1
2 #include <stdio.h>
3 #include <limits.h> /* for PATH_MAX */
4 #define __USE_GNU /* for strndup */
5 #include <string.h> /* for strdup */
6 #include <stdlib.h> /* getenv */
7
8 #include "pnd_container.h"
9 #include "pnd_conf.h"
10 #include "pnd_discovery.h"
11 #include "pnd_notify.h"
12 #include "pnd_dbusnotify.h"
13 #include "pnd_logger.h"
14
15 #include "mmenu.h"
16 #include "mmcustom_cats.h"
17
18 mmcustom_cat_t mmcustom_complete [ MMCUSTOM_CATS_MAX ];
19 unsigned int mmcustom_count = 0;
20
21 pnd_conf_handle g_custom_h = 0;
22
23 char *mmcustom_determine_path ( void ) {
24   char *home = getenv ( "HOME" );
25   static char path [ PATH_MAX ];
26   bzero ( path, PATH_MAX );
27
28   snprintf ( path, PATH_MAX - 1, "%s/%s", home ? home : ".", MMCUSTOM_CATS_PREF_FILENAME );
29
30   return ( path );
31 }
32
33 static unsigned char loaded = 0;
34 unsigned char mmcustom_setup ( void ) {
35
36   if ( ! loaded ) {
37     loaded = 1;
38
39     // inhale conf file
40     char *path = mmcustom_determine_path();
41
42     g_custom_h = pnd_conf_fetch_by_path ( path );
43
44     if ( ! g_custom_h ) {
45       pnd_log ( pndn_rem, "Custom category conf file %s not found; is okay.\n", path );
46       return ( 1 ); // file does not exist most likely
47     }
48
49     // find its head; if no head (empty file), bail
50     char *iter = pnd_box_get_head ( g_custom_h );
51
52     if ( ! iter ) {
53       pnd_log ( pndn_rem, "Custom category conf file %s is empty. Fine.\n", path );
54       return ( 1 );
55     }
56
57     // walk the conf, plucking out the values
58     while ( iter ) {
59       char *k = pnd_box_get_key ( iter );
60
61       // does this entry look like it is a custom category?
62       if ( strncmp ( k, MMCUSTOM_CATS_SECTION, strlen ( MMCUSTOM_CATS_SECTION ) ) == 0 ) {
63         // determine the actual category name part
64         k += ( strlen ( MMCUSTOM_CATS_SECTION ) + 1 );
65
66         mmcustom_complete [ mmcustom_count ].cat = strdup ( k );
67         if ( iter && strcmp ( iter, MMCUSTOM_CATS_NOCAT ) != 0 ) {
68           mmcustom_complete [ mmcustom_count ].parent_cat = strdup ( iter );
69         } else {
70           mmcustom_complete [ mmcustom_count ].parent_cat = NULL;
71         }
72
73         mmcustom_count += 1;
74
75       }
76
77       // next!
78       iter = pnd_box_get_next ( iter );
79
80     } // while
81
82     pnd_log ( pndn_rem, "Found %u custom categories.\n", mmcustom_count );
83
84   } // loaded already?
85
86   return ( 1 );
87 }
88
89 void mmcustom_shutdown ( void ) {
90
91   bzero ( mmcustom_complete, sizeof(mmcustom_cat_t) * MMCUSTOM_CATS_MAX );
92   mmcustom_count = 0;
93   loaded = 0;
94
95   return;
96 }
97
98 unsigned char mmcustom_write ( char *fullpath /* if NULL, uses canonical location */ ) {
99
100   if ( ! fullpath ) {
101     fullpath = mmcustom_determine_path();
102   }
103
104   FILE *f = fopen ( fullpath, "w" );
105
106   if ( ! f ) {
107     return ( 0 );
108   }
109
110   int i;
111   for ( i = 0; i < mmcustom_count; i++ ) {
112     if ( mmcustom_complete [ i ].cat ) {
113       fprintf ( f, "%s.%s\t%s\n", MMCUSTOM_CATS_SECTION, mmcustom_complete [ i ].cat, mmcustom_complete [ i ].parent_cat ? mmcustom_complete [ i ].parent_cat : MMCUSTOM_CATS_NOCAT );
114     }
115   }
116
117   fclose ( f );
118
119   return ( 1 );
120 }
121
122 mmcustom_cat_t *mmcustom_query ( char *name, char *parentcatname ) {
123   int i;
124
125   // search for the cat/parent combination
126   for ( i = 0; i < mmcustom_count; i++ ) {
127     mmcustom_cat_t *p = &(mmcustom_complete [ i ]);
128
129     if ( strcasecmp ( p -> cat, name ) == 0 ) {
130
131       if ( parentcatname == NULL && p -> parent_cat == NULL ) {
132         return ( p );
133       } else if ( parentcatname && p -> parent_cat && strcasecmp ( p -> parent_cat, parentcatname ) == 0 ) {
134         return ( p );
135       }
136
137     }
138
139   } // for
140
141   return ( NULL );
142 }
143
144 mmcustom_cat_t *mmcustom_register ( char *catname, char *parentcatname ) {
145   mmcustom_complete [ mmcustom_count ].cat = strdup ( catname );
146   if ( parentcatname ) {
147     mmcustom_complete [ mmcustom_count ].parent_cat = strdup ( parentcatname );
148   }
149   mmcustom_count += 1;
150   return ( &(mmcustom_complete [ mmcustom_count - 1 ]) );
151 }
152
153 unsigned int mmcustom_count_subcats ( char *catname ) {
154   int i;
155   unsigned int counter = 0;
156
157   for ( i = 0; i < mmcustom_count; i++ ) {
158
159     if ( mmcustom_complete [ i ].parent_cat && strcasecmp ( mmcustom_complete [ i ].parent_cat, catname ) == 0 ) {
160       counter++;
161     }
162
163   }
164
165   return ( counter );
166 }
167
168 void mmcustom_unregister ( char *catname, char *parentcatname ) {
169   int i;
170   int parent_index = -1;
171
172   if ( parentcatname ) {
173     pnd_log ( pndn_warning, "Goal: Remove subcat %s of %s\n", catname, parentcatname );
174   } else {
175     pnd_log ( pndn_warning, "Goal: Remove parent cat %s and descendants\n", catname );
176   }
177
178   for ( i = 0; i < mmcustom_count; i++ ) {
179
180     // killing a parent cat, or just a subcat?
181     if ( parentcatname ) {
182
183       // killing a subcat, so match cat+subcat to kill
184       if ( mmcustom_complete [ i ].cat && strcmp ( mmcustom_complete [ i ].cat, catname ) == 0 &&
185            mmcustom_complete [ i ].parent_cat && strcasecmp ( mmcustom_complete [ i ].parent_cat, parentcatname ) == 0 )
186       {
187         pnd_log ( pndn_warning, "  Removing subcat: %s of %s\n", catname, parentcatname );
188         free ( mmcustom_complete [ i ].cat );
189         mmcustom_complete [ i ].cat = NULL;
190         break;
191       }
192
193     } else {
194
195       // killing a parent cat, so kill it, and any children of it
196       if ( mmcustom_complete [ i ].parent_cat == NULL &&
197            mmcustom_complete [ i ].cat &&
198            strcmp ( mmcustom_complete [ i ].cat, catname ) == 0 )
199       {
200         // flag the prent for future death (we need its name for now, since the caller is using it)
201         parent_index = i;
202       }
203       else if ( mmcustom_complete [ i ].cat &&
204                 mmcustom_complete [ i ].parent_cat &&
205                 strcmp ( mmcustom_complete [ i ].parent_cat, catname ) == 0 )
206       {
207         // kill children of it
208         pnd_log ( pndn_warning, "  Removing cascading subcat: %s of %s\n", mmcustom_complete [ i ].cat, mmcustom_complete [ i ].parent_cat );
209         free ( mmcustom_complete [ i ].cat );
210         mmcustom_complete [ i ].cat = NULL;
211       }
212
213     }
214
215   } // for
216
217   // kill the actual cat itself
218   if ( i >= 0 ) {
219     pnd_log ( pndn_warning, "  Removing cat: %s\n", catname );
220     free ( mmcustom_complete [ i ].cat );
221     mmcustom_complete [ i ].cat = NULL;
222   }
223
224   return;
225 }