1 /*
2 * Bookmarks server (chat version).
3 *
4 * NOTE: this code illustrates how to make a dpi-program.
5 *
6 * Copyright 2002-2007 Jorge Arellano Cid <jcid@dillo.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 */
14
15 /* TODO: this server is not assembling the received packets.
16 * This means it currently expects dillo to send full dpi tags
17 * within the socket; if that fails, everything stops.
18 * This is not hard to fix, mainly is a matter of expecting the
19 * final '>' of a tag.
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stddef.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <sys/socket.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <sys/un.h>
33 #include <time.h>
34 #include <netdb.h>
35 #include <fcntl.h>
36 #include <signal.h>
37 #include "../dpip/dpip.h"
38 #include "dpiutil.h"
39
40
41 /*
42 * Debugging macros
43 */
44 #define _MSG(...)
45 #define MSG(...) printf("[bookmarks dpi]: " __VA_ARGS__)
46
47 #define DOCTYPE \
48 "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>\n"
49
50 /*
51 * Notes on character escaping:
52 * - Basically things are saved unescaped and escaped when in memory.
53 * - &<>"' are escaped in titles and sections and saved unescaped.
54 * - ' is escaped as %27 in URLs and saved escaped.
55 */
56 typedef struct {
57 int key;
58 int section;
59 char *url;
60 char *title;
61 } BmRec;
62
63 typedef struct {
64 int section;
65 char *title;
66
67 int o_sec; /* private, for normalization */
68 } BmSec;
69
70
71 /*
72 * Local data
73 */
74 static char *Header = "Content-type: text/html\n\n";
75 static char *BmFile = NULL;
76 static time_t BmFileTimeStamp = 0;
77 static Dlist *B_bms = NULL;
78 static int bm_key = 0;
79
80 static Dlist *B_secs = NULL;
81 static int sec_key = 0;
82
83 static int MODIFY_PAGE_NUM = 1;
84
85
86 /*
87 * Forward declarations
88 */
89
90
91 /* -- HTML templates ------------------------------------------------------- */
92
93 static const char *mainpage_header =
94 DOCTYPE
95 "<html>\n"
96 "<head>\n"
97 "<title>Bookmarks</title>\n"
98 "</head>\n"
99 "<body id='dillo_bm' bgcolor='#778899' link='black' vlink='brown'>\n"
100 "<table border='1' cellpadding='0' width='100%'>\n"
101 " <tr><td>\n"
102 " <table width='100%' bgcolor='#b4b4b4'>\n"
103 " <tr>\n"
104 " <td> Bookmarks :: </td>\n"
105 " <td align='right'>\n"
106 " [<a href='dpi:/bm/modify'>modify</a>]\n"
107 " </td></tr>\n"
108 " </table></td></tr>\n"
109 "</table>\n"
110 "<br>\n";
111
112 static const char *modifypage_header =
113 DOCTYPE
114 "<html>\n"
115 "<head>\n"
116 "<title>Bookmarks</title>\n"
117 "</head>\n"
118 "<body id='dillo_bm' bgcolor='#778899' link='black' vlink='brown'>\n"
119 "<table border='1' cellpadding='0' width='100%'>\n"
120 " <tr><td>\n"
121 " <table width='100%' bgcolor='#b4b4b4'>\n"
122 " <tr>\n"
123 " <td> Bookmarks :: modify</td>\n"
124 " <td align='right'>\n"
125 " [<a href='dpi:/bm/'>cancel</a>]\n"
126 " </td>\n"
127 " </tr>\n"
128 " </table></td></tr> \n"
129 "</table> \n"
130 "\n"
131 "<form action='modify'>\n"
132 "<table width='100%' border='1' cellpadding='0'>\n"
133 " <tr style='background-color: teal'>\n"
134 " <td>\n"
135 " <b>Select an operation</b>\n"
136 " <select name='operation'>\n"
137 " <option value='none' selected>--\n"
138 " <option value='delete'>Delete\n"
139 " <option value='move'>Move\n"
140 " <option value='modify'>Modify\n"
141 " <option value='add_sec'>Add Section\n"
142 " <option value='add_url'>Add URL\n"
143 " </select>\n"
144 " <b>, mark its operands, and</b>\n"
145 " <input type='submit' name='submit' value='submit.'>\n"
146 " </td>\n"
147 " </tr>\n"
148 "</table>\n";
149
150 static const char *mainpage_sections_header =
151 "<table border='1' cellpadding='0' cellspacing='20' width='100%'>\n"
152 " <tr valign='top'>\n"
153 " <td>\n"
154 " <table bgcolor='#b4b4b4' border='2' cellpadding='4' cellspacing='1'>\n"
155 " <tr><td>\n"
156 " <table width='100%' bgcolor='#b4b4b4'>\n"
157 " <tr><td><small>Sections:</small></td></tr></table></td></tr>\n";
158
159 static const char *modifypage_sections_header =
160 "<table border='1' cellpadding='0' cellspacing='20' width='100%'>\n"
161 " <tr valign='top'>\n"
162 " <td>\n"
163 " <table bgcolor='#b4b4b4' border='1'>\n"
164 " <tr><td>\n"
165 " <table width='100%' bgcolor='#b4b4b4'>\n"
166 " <tr><td><small>Sections:</small></td></tr></table></td></tr>\n";
167
168 static const char *mainpage_sections_item =
169 " <tr><td align='center'>\n"
170 " <a href='#s%d'>%s</a></td></tr>\n";
171
172 static const char *modifypage_sections_item =
173 " <tr><td>\n"
174 " <table width='100%%'>\n"
175 " <tr align='center'>"
176 " <td><input type='checkbox' name='s%d'></td>\n"
177 " <td width='100%%'><a href='#s%d'>%s</a></td></tr></table></td></tr>\n";
178
179 static const char *mainpage_sections_footer =
180 " </table>\n";
181
182 static const char *modifypage_sections_footer =
183 " </table>\n";
184
185 static const char *mainpage_middle1 =
186 " </td>\n"
187 " <td width='100%'>\n";
188
189 static const char *modifypage_middle1 =
190 " </td>\n"
191 " <td width='100%'>\n";
192
193 static const char *mainpage_section_card_header =
194 " <a name='s%d'></a>\n"
195 " <table bgcolor='#bfbfbf' width='100%%' cellspacing='2'>\n"
196 " <tr>\n"
197 " <td bgcolor='#bf0c0c'><font color='white'><b>\n"
198 " %s </b></font></td>\n"
199 " <td bgcolor='white' width='100%%'> </td></tr>\n";
200
201 static const char *modifypage_section_card_header =
202 " <a name='s%d'></a>\n"
203 " <table bgcolor='#bfbfbf' width='100%%' cellspacing='2'>\n"
204 " <tr>\n"
205 " <td bgcolor='#bf0c0c'><font color='white'><b>\n"
206 " %s </b></font></td>\n"
207 " <td bgcolor='white' width='100%%'> </td></tr>\n";
208
209 static const char *mainpage_section_card_item =
210 " <tr><td colspan='2'>\n"
211 " <a href='%s'>%s</a> </td></tr>\n";
212
213 static const char *modifypage_section_card_item =
214 " <tr>\n"
215 " <td colspan='2'><input type='checkbox' name='url%d'>\n"
216 " <a href='%s'>%s</a></td></tr>\n";
217
218 static const char *mainpage_section_card_footer =
219 " </table>\n"
220 " <hr>\n";
221
222 static const char *modifypage_section_card_footer =
223 " </table>\n"
224 " <hr>\n";
225
226 static const char *mainpage_footer =
227 " </td>\n"
228 " </tr>\n"
229 "</table>\n"
230 "</body>\n"
231 "</html>\n";
232
233 static const char *modifypage_footer =
234 " </td>\n"
235 " </tr>\n"
236 "</table>\n"
237 "</form>\n"
238 "</body>\n"
239 "</html>\n";
240
241 /* ------------------------------------------------------------------------- */
242 static const char *modifypage_add_section_page =
243 DOCTYPE
244 "<html>\n"
245 "<head>\n"
246 "<title>Bookmarks</title>\n"
247 "</head>\n"
248 "<body id='dillo_bm' bgcolor='#778899' link='black' vlink='brown'>\n"
249 "<table border='1' cellpadding='0' width='100%'>\n"
250 " <tr><td colspan='2'>\n"
251 " <table bgcolor='#b4b4b4' width='100%'>\n"
252 " <tr>\n"
253 " <td bgcolor='#b4b4b4'>\n"
254 " Modify bookmarks :: add section\n"
255 " </td>\n"
256 " <td align='right'>\n"
257 " [<a href='dpi:/bm/'>cancel</a>]\n"
258 " </td>\n"
259 " </tr>\n"
260 " </table></td></tr>\n"
261 "</table>\n"
262 "<br>\n"
263 "<form action='modify'>\n"
264 " <input type='hidden' name='operation' value='add_section'>\n"
265 "<table border='1' width='100%'>\n"
266 " <tr>\n"
267 " <td bgcolor='olive'><b>New section:</b></td>\n"
268 " <td bgcolor='white' width='100%'></td></tr>\n"
269 "</table>\n"
270 "<table width='100%' cellpadding='10'>\n"
271 "<tr><td>\n"
272 " <table width='100%' bgcolor='teal'>\n"
273 " <tr>\n"
274 " <td>Title:</td>\n"
275 " <td><input type='text' name='title' size='64'></td></tr>\n"
276 " </table>\n"
277 " </td></tr>\n"
278 "</table>\n"
279 "<table width='100%' cellpadding='4' border='0'>\n"
280 "<tr><td bgcolor='#a0a0a0'>\n"
281 " <input type='submit' name='submit' value='submit.'></td></tr>\n"
282 "</table>\n"
283 "</form>\n"
284 "</body>\n"
285 "</html>\n"
286 "\n";
287
288 /* ------------------------------------------------------------------------- */
289 static const char *modifypage_update_header =
290 DOCTYPE
291 "<html>\n"
292 "<head>\n"
293 "<title>Bookmarks</title>\n"
294 "</head>\n"
295 "<body id='dillo_bm' bgcolor='#778899' link='black' vlink='brown'>\n"
296 "<table border='1' cellpadding='0' width='100%'>\n"
297 " <tr><td colspan='2'>\n"
298 " <table bgcolor='#b4b4b4' width='100%'>\n"
299 " <tr><td bgcolor='#b4b4b4'> Modify bookmarks :: update\n"
300 " </td>\n"
301 " <td align='right'>\n"
302 " [<a href='dpi:/bm/'>cancel</a>]\n"
303 " </td>\n"
304 " </tr>\n"
305 " </table></td></tr>\n"
306 "</table>\n"
307 "<br>\n"
308 "<form action='modify'>\n"
309 "<input type='hidden' name='operation' value='modify2'>\n";
310
311 static const char *modifypage_update_title =
312 "<table border='1' width='100%%'>\n"
313 " <tr>\n"
314 " <td bgcolor='olive'><b>%s</b></td>\n"
315 " <td bgcolor='white' width='100%%'></td></tr>\n"
316 "</table>\n";
317
318 static const char *modifypage_update_item_header =
319 "<table width='100%' cellpadding='10'>\n";
320
321 static const char *modifypage_update_item =
322 "<tr><td>\n"
323 " <table width='100%%' bgcolor='teal'>\n"
324 " <tr>\n"
325 " <td>Title:</td>\n"
326 " <td><input type='text' name='title%d' size='64'\n"
327 " value='%s'></td></tr>\n"
328 " <tr>\n"
329 " <td>URL:</td>\n"
330 " <td>%s</td></tr>\n"
331 " </table>\n"
332 " </td></tr>\n";
333
334 static const char *modifypage_update_item2 =
335 "<tr><td>\n"
336 " <table width='100%%' bgcolor='teal'>\n"
337 " <tr>\n"
338 " <td>Title:</td>\n"
339 " <td><input type='text' name='s%d' size='64'\n"
340 " value='%s'></td></tr>\n"
341 " </table>\n"
342 " </td></tr>\n";
343
344 static const char *modifypage_update_item_footer =
345 "</table>\n";
346
347 static const char *modifypage_update_footer =
348 "<table width='100%' cellpadding='4' border='0'>\n"
349 "<tr><td bgcolor='#a0a0a0'>\n"
350 " <input type='submit' name='submit' value='submit.'></td></tr>\n"
351 "</table>\n"
352 "</form>\n"
353 "</body>\n"
354 "</html>\n";
355
356 /* ------------------------------------------------------------------------- */
357 static const char *modifypage_add_url =
358 DOCTYPE
359 "<html>\n"
360 "<head>\n"
361 "<title>Bookmarks</title>\n"
362 "</head>\n"
363 "<body id='dillo_bm' bgcolor='#778899' link='black' vlink='brown'>\n"
364 "<table border='1' cellpadding='0' width='100%'>\n"
365 " <tr><td colspan='2'>\n"
366 " <table bgcolor='#b4b4b4' width='100%'>\n"
367 " <tr><td bgcolor='#b4b4b4'> Modify bookmarks :: add url\n"
368 " </td>\n"
369 " <td align='right'>\n"
370 " [<a href='dpi:/bm/'>cancel</a>]\n"
371 " </td>\n"
372 " </tr>\n"
373 " </table></td></tr>\n"
374 "</table>\n"
375 "<br>\n"
376 "<form action='modify'>\n"
377 "<input type='hidden' name='operation' value='add_url2'>\n"
378 "<table border='1' width='100%'>\n"
379 " <tr>\n"
380 " <td bgcolor='olive'><b>Add url:</b></td>\n"
381 " <td bgcolor='white' width='100%'></td></tr>\n"
382 "</table>\n"
383 "<table width='100%' cellpadding='10'>\n"
384 "<tr><td>\n"
385 " <table width='100%' bgcolor='teal'>\n"
386 " <tr>\n"
387 " <td>Title:</td>\n"
388 " <td><input type='text' name='title' size='64'></td></tr>\n"
389 " <tr>\n"
390 " <td>URL:</td>\n"
391 " <td><input type='text' name='url' size='64'></td></tr>\n"
392 " </table>\n"
393 " </td></tr>\n"
394 "</table>\n"
395 "<table width='100%' cellpadding='4' border='0'>\n"
396 "<tr><td bgcolor='#a0a0a0'>\n"
397 " <input type='submit' name='submit' value='submit.'></td></tr>\n"
398 "</table>\n"
399 "</form>\n"
400 "</body>\n"
401 "</html>\n";
402
403
404 /* ------------------------------------------------------------------------- */
405
406 /*
407 * Return a new string with spaces changed with
408 */
make_one_line_str(char * str)409 static char *make_one_line_str(char *str)
410 {
411 char *new_str;
412 int i, j, n;
413
414 for (i = 0, n = 0; str[i]; ++i)
415 if (str[i] == ' ')
416 ++n;
417
418 new_str = dNew(char, strlen(str) + 6*n + 1);
419 new_str[0] = 0;
420
421 for (i = 0, j = 0; str[i]; ++i) {
422 if (str[i] == ' ') {
423 strcpy(new_str + j, " ");
424 j += 6;
425 } else {
426 new_str[j] = str[i];
427 new_str[++j] = 0;
428 }
429 }
430
431 return new_str;
432 }
433
434 /*
435 * Given an urlencoded string, return it to the original version.
436 */
Unencode_str(char * e_str)437 static void Unencode_str(char *e_str)
438 {
439 char *p, *e;
440
441 for (p = e = e_str; *e; e++, p++) {
442 if (*e == '+') {
443 *p = ' ';
444 } else if (*e == '%') {
445 if (dStrnAsciiCasecmp(e, "%0D%0A", 6) == 0) {
446 *p = '\n';
447 e += 5;
448 } else {
449 *p = (isdigit(e[1]) ? (e[1] - '0') : (e[1] - 'A' + 10)) * 16 +
450 (isdigit(e[2]) ? (e[2] - '0') : (e[2] - 'A' + 10));
451 e += 2;
452 }
453 } else {
454 *p = *e;
455 }
456 }
457 *p = 0;
458 }
459
460 /*
461 * Send a short message to dillo's status bar.
462 */
Bmsrv_dpi_send_status_msg(Dsh * sh,char * str)463 static int Bmsrv_dpi_send_status_msg(Dsh *sh, char *str)
464 {
465 int st;
466 char *d_cmd;
467
468 d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s", "send_status_message", str);
469 st = a_Dpip_dsh_write_str(sh, 1, d_cmd);
470 dFree(d_cmd);
471 return st;
472 }
473
474 /* -- ADT for bookmarks ---------------------------------------------------- */
475 /*
476 * Compare function for searching a bookmark by its key
477 */
Bms_node_by_key_cmp(const void * node,const void * key)478 static int Bms_node_by_key_cmp(const void *node, const void *key)
479 {
480 return ((BmRec *)node)->key - VOIDP2INT(key);
481 }
482
483 /*
484 * Compare function for searching a bookmark by section
485 */
Bms_node_by_section_cmp(const void * node,const void * key)486 static int Bms_node_by_section_cmp(const void *node, const void *key)
487 {
488 return ((BmRec *)node)->section - VOIDP2INT(key);
489 }
490
491 /*
492 * Compare function for searching a section by its number
493 */
Bms_sec_by_number_cmp(const void * node,const void * key)494 static int Bms_sec_by_number_cmp(const void *node, const void *key)
495 {
496 return ((BmSec *)node)->section - VOIDP2INT(key);
497 }
498
499 /*
500 * Return the Bm record by key
501 */
Bms_get(int key)502 static BmRec *Bms_get(int key)
503 {
504 return dList_find_custom(B_bms, INT2VOIDP(key), Bms_node_by_key_cmp);
505 }
506
507 /*
508 * Return the Section record by key
509 */
Bms_get_sec(int key)510 static BmSec *Bms_get_sec(int key)
511 {
512 return dList_find_custom(B_secs, INT2VOIDP(key), Bms_sec_by_number_cmp);
513 }
514
515 /*
516 * Add a bookmark
517 */
Bms_add(int section,char * url,char * title)518 static void Bms_add(int section, char *url, char *title)
519 {
520 BmRec *bm_node;
521
522 bm_node = dNew(BmRec, 1);
523 bm_node->key = ++bm_key;
524 bm_node->section = section;
525 bm_node->url = Escape_uri_str(url, "'");
526 bm_node->title = Escape_html_str(title);
527 dList_append(B_bms, bm_node);
528 }
529
530 /*
531 * Add a section
532 */
Bms_sec_add(char * title)533 static void Bms_sec_add(char *title)
534 {
535 BmSec *sec_node;
536
537 sec_node = dNew(BmSec, 1);
538 sec_node->section = sec_key++;
539 sec_node->title = Escape_html_str(title);
540 dList_append(B_secs, sec_node);
541 }
542
543 /*
544 * Delete a bookmark by its key
545 */
Bms_del(int key)546 static void Bms_del(int key)
547 {
548 BmRec *bm_node;
549
550 bm_node = dList_find_custom(B_bms, INT2VOIDP(key), Bms_node_by_key_cmp);
551 if (bm_node) {
552 dList_remove(B_bms, bm_node);
553 dFree(bm_node->title);
554 dFree(bm_node->url);
555 dFree(bm_node);
556 }
557 if (dList_length(B_bms) == 0)
558 bm_key = 0;
559 }
560
561 /*
562 * Delete a section and its bookmarks by section number
563 */
Bms_sec_del(int section)564 static void Bms_sec_del(int section)
565 {
566 BmSec *sec_node;
567 BmRec *bm_node;
568
569 sec_node = dList_find_custom(B_secs, INT2VOIDP(section),
570 Bms_sec_by_number_cmp);
571 if (sec_node) {
572 dList_remove(B_secs, sec_node);
573 dFree(sec_node->title);
574 dFree(sec_node);
575
576 /* iterate B_bms and remove those that match the section */
577 while ((bm_node = dList_find_custom(B_bms, INT2VOIDP(section),
578 Bms_node_by_section_cmp))) {
579 Bms_del(bm_node->key);
580 }
581 }
582 if (dList_length(B_secs) == 0)
583 sec_key = 0;
584 }
585
586 /*
587 * Move a bookmark to another section
588 */
Bms_move(int key,int target_section)589 static void Bms_move(int key, int target_section)
590 {
591 BmRec *bm_node;
592
593 bm_node = dList_find_custom(B_bms, INT2VOIDP(key), Bms_node_by_key_cmp);
594 if (bm_node) {
595 bm_node->section = target_section;
596 }
597 }
598
599 /*
600 * Update a bookmark title by key
601 */
Bms_update_title(int key,char * n_title)602 static void Bms_update_title(int key, char *n_title)
603 {
604 BmRec *bm_node;
605
606 bm_node = dList_find_custom(B_bms, INT2VOIDP(key), Bms_node_by_key_cmp);
607 if (bm_node) {
608 dFree(bm_node->title);
609 bm_node->title = Escape_html_str(n_title);
610 }
611 }
612
613 /*
614 * Update a section title by key
615 */
Bms_update_sec_title(int key,char * n_title)616 static void Bms_update_sec_title(int key, char *n_title)
617 {
618 BmSec *sec_node;
619
620 sec_node = dList_find_custom(B_secs, INT2VOIDP(key), Bms_sec_by_number_cmp);
621 if (sec_node) {
622 dFree(sec_node->title);
623 sec_node->title = Escape_html_str(n_title);
624 }
625 }
626
627 /*
628 * Free all the bookmarks data (bookmarks and sections)
629 */
Bms_free(void)630 static void Bms_free(void)
631 {
632 BmRec *bm_node;
633 BmSec *sec_node;
634
635 /* free B_bms */
636 while ((bm_node = dList_nth_data(B_bms, 0))) {
637 Bms_del(bm_node->key);
638 }
639 /* free B_secs */
640 while ((sec_node = dList_nth_data(B_secs, 0))) {
641 Bms_sec_del(sec_node->section);
642 }
643 }
644
645 /*
646 * Enforce increasing correlative section numbers with no jumps.
647 */
Bms_normalize(void)648 static void Bms_normalize(void)
649 {
650 BmRec *bm_node;
651 BmSec *sec_node;
652 int i, j;
653
654 /* we need at least one section */
655 if (dList_length(B_secs) == 0)
656 Bms_sec_add("Unclassified");
657
658 /* make correlative section numbers */
659 for (i = 0; (sec_node = dList_nth_data(B_secs, i)); ++i) {
660 sec_node->o_sec = sec_node->section;
661 sec_node->section = i;
662 }
663
664 /* iterate B_secs and make the changes in B_bms */
665 for (i = 0; (sec_node = dList_nth_data(B_secs, i)); ++i) {
666 if (sec_node->section != sec_node->o_sec) {
667 /* update section numbers */
668 for (j = 0; (bm_node = dList_nth_data(B_bms, j)); ++j) {
669 if (bm_node->section == sec_node->o_sec)
670 bm_node->section = sec_node->section;
671 }
672 }
673 }
674 }
675
676 /* -- Load bookmarks file -------------------------------------------------- */
677
678 /*
679 * If there's no "bm.txt", create one from "bookmarks.html".
680 */
Bms_check_import(void)681 static void Bms_check_import(void)
682 {
683 char *OldBmFile;
684 char *cmd1 =
685 "echo \":s0: Unclassified\" > %s";
686 char *cmd2 =
687 "grep -i \"href\" %s | "
688 "sed -e 's/<li><A HREF=\"/s0 /' -e 's/\">/ /' -e 's/<.*$//' >> %s";
689 Dstr *dstr = dStr_new("");
690 int rc;
691
692
693 if (access(BmFile, F_OK) != 0) {
694 OldBmFile = dStrconcat(dGethomedir(), "/.dillo/bookmarks.html", NULL);
695 if (access(OldBmFile, F_OK) == 0) {
696 dStr_sprintf(dstr, cmd1, BmFile);
697 rc = system(dstr->str);
698 if (rc == 127) {
699 MSG("Bookmarks: /bin/sh could not be executed\n");
700 } else if (rc == -1) {
701 MSG("Bookmarks: process creation failure: %s\n",
702 dStrerror(errno));
703 }
704 dStr_sprintf(dstr, cmd2, OldBmFile, BmFile);
705 rc = system(dstr->str);
706 if (rc == 127) {
707 MSG("Bookmarks: /bin/sh could not be executed\n");
708 } else if (rc == -1) {
709 MSG("Bookmarks: process creation failure: %s\n",
710 dStrerror(errno));
711 }
712
713 dStr_free(dstr, TRUE);
714 dFree(OldBmFile);
715 }
716 }
717 }
718
719 /*
720 * Load bookmarks data from a file
721 */
Bms_load(void)722 static int Bms_load(void)
723 {
724 FILE *BmTxt;
725 char *buf, *p, *url, *title, *u_title;
726 int section;
727 struct stat TimeStamp;
728
729 /* clear current bookmarks */
730 Bms_free();
731
732 /* open bm file */
733 if (!(BmTxt = fopen(BmFile, "r"))) {
734 perror("[fopen]");
735 return 1;
736 }
737
738 /* load bm file into memory */
739 while ((buf = dGetline(BmTxt)) != NULL) {
740 if (buf[0] == 's') {
741 /* get section, url and title */
742 section = strtol(buf + 1, NULL, 10);
743 p = strchr(buf, ' '); *p = 0;
744 url = ++p;
745 p = strchr(p, ' '); *p = 0;
746 title = ++p;
747 p = strchr(p, '\n'); *p = 0;
748 u_title = Unescape_html_str(title);
749 Bms_add(section, url, u_title);
750 dFree(u_title);
751
752 } else if (buf[0] == ':' && buf[1] == 's') {
753 /* section = strtol(buf + 2, NULL, 10); */
754 p = strchr(buf + 2, ' ');
755 title = ++p;
756 p = strchr(p, '\n'); *p = 0;
757 Bms_sec_add(title);
758
759 } else {
760 MSG("Syntax error in bookmarks file:\n %s", buf);
761 }
762 dFree(buf);
763 }
764 fclose(BmTxt);
765
766 /* keep track of the timestamp */
767 stat(BmFile, &TimeStamp);
768 BmFileTimeStamp = TimeStamp.st_mtime;
769
770 return 0;
771 }
772
773 /*
774 * Load bookmarks data if:
775 * - file timestamp is newer than ours or
776 * - we haven't loaded anything yet :)
777 */
Bms_cond_load(void)778 static int Bms_cond_load(void)
779 {
780 int st = 0;
781 struct stat TimeStamp;
782
783 if (stat(BmFile, &TimeStamp) != 0) {
784 /* try to import... */
785 Bms_check_import();
786 if (stat(BmFile, &TimeStamp) != 0)
787 TimeStamp.st_mtime = 0;
788 }
789
790 if (!BmFileTimeStamp || !dList_length(B_bms) || !dList_length(B_secs) ||
791 BmFileTimeStamp < TimeStamp.st_mtime) {
792 Bms_load();
793 st = 1;
794 }
795 return st;
796 }
797
798 /* -- Save bookmarks file -------------------------------------------------- */
799
800 /*
801 * Update the bookmarks file from memory contents
802 * Return code: { 0:OK, 1:Abort }
803 */
Bms_save(void)804 static int Bms_save(void)
805 {
806 FILE *BmTxt;
807 BmRec *bm_node;
808 BmSec *sec_node;
809 struct stat BmStat;
810 char *u_title;
811 int i, j;
812 Dstr *dstr = dStr_new("");
813
814 /* make a safety backup */
815 if (stat(BmFile, &BmStat) == 0 && BmStat.st_size > 256) {
816 char *BmFileBak = dStrconcat(BmFile, ".bak", NULL);
817 rename(BmFile, BmFileBak);
818 dFree(BmFileBak);
819 }
820
821 /* open bm file */
822 if (!(BmTxt = fopen(BmFile, "w"))) {
823 perror("[fopen]");
824 return 1;
825 }
826
827 /* normalize */
828 Bms_normalize();
829
830 /* save sections */
831 for (i = 0; (sec_node = dList_nth_data(B_secs, i)); ++i) {
832 u_title = Unescape_html_str(sec_node->title);
833 dStr_sprintf(dstr, ":s%d: %s\n", sec_node->section, u_title);
834 fwrite(dstr->str, (size_t)dstr->len, 1, BmTxt);
835 dFree(u_title);
836 }
837
838 /* save bookmarks (section url title) */
839 for (i = 0; (sec_node = dList_nth_data(B_secs, i)); ++i) {
840 for (j = 0; (bm_node = dList_nth_data(B_bms, j)); ++j) {
841 if (bm_node->section == sec_node->section) {
842 u_title = Unescape_html_str(bm_node->title);
843 dStr_sprintf(dstr, "s%d %s %s\n",
844 bm_node->section, bm_node->url, u_title);
845 fwrite(dstr->str, (size_t)dstr->len, 1, BmTxt);
846 dFree(u_title);
847 }
848 }
849 }
850
851 dStr_free(dstr, TRUE);
852 fclose(BmTxt);
853
854 /* keep track of the timestamp */
855 stat(BmFile, &BmStat);
856 BmFileTimeStamp = BmStat.st_mtime;
857
858 return 0;
859 }
860
861 /* -- Add bookmark --------------------------------------------------------- */
862
863 /*
864 * Add a new bookmark to DB :)
865 */
Bmsrv_add_bm(Dsh * sh,char * url,char * title)866 static int Bmsrv_add_bm(Dsh *sh, char *url, char *title)
867 {
868 char *u_title;
869 char *msg="Added bookmark!";
870 int section = 0;
871
872 /* Add in memory */
873 u_title = Unescape_html_str(title);
874 Bms_add(section, url, u_title);
875 dFree(u_title);
876
877 /* Write to file */
878 Bms_save();
879
880 if (Bmsrv_dpi_send_status_msg(sh, msg))
881 return 1;
882
883 return 0;
884 }
885
886 /* -- Modify --------------------------------------------------------------- */
887
888 /*
889 * Count how many sections and urls were marked in a request
890 */
Bmsrv_count_urls_and_sections(char * url,int * n_sec,int * n_url)891 static void Bmsrv_count_urls_and_sections(char *url, int *n_sec, int *n_url)
892 {
893 char *p, *q;
894 int i;
895
896 /* Check marked urls and sections */
897 *n_sec = *n_url = 0;
898 if ((p = strchr(url, '?'))) {
899 for (q = p; (q = strstr(q, "&url")); ++q) {
900 for (i = 0; isdigit(q[4+i]); ++i);
901 *n_url += (q[4+i] == '=') ? 1 : 0;
902 }
903 for (q = p; (q = strstr(q, "&s")); ++q) {
904 for (i = 0; isdigit(q[2+i]); ++i);
905 *n_sec += (q[2+i] == '=') ? 1 : 0;
906 }
907 }
908 }
909
910 /*
911 * Send a dpi reload request
912 * Return code: { 0:OK, 1:Abort, 2:Close }
913 */
Bmsrv_send_reload_request(Dsh * sh,char * url)914 static int Bmsrv_send_reload_request(Dsh *sh, char *url)
915 {
916 int st;
917 char *d_cmd;
918
919 d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "reload_request", url);
920 st = a_Dpip_dsh_write_str(sh, 1, d_cmd) ? 1 : 0;
921 dFree(d_cmd);
922 return st;
923 }
924
925 /*
926 * Send the HTML for the modify page
927 * Return code: { 0:OK, 1:Abort, 2:Close }
928 */
Bmsrv_send_modify_page(Dsh * sh)929 static int Bmsrv_send_modify_page(Dsh *sh)
930 {
931 static Dstr *dstr = NULL;
932 char *l_title;
933 BmSec *sec_node;
934 BmRec *bm_node;
935 int i, j;
936
937 if (!dstr)
938 dstr = dStr_new("");
939
940 /* send modify page header */
941 if (a_Dpip_dsh_write_str(sh, 0, modifypage_header))
942 return 1;
943
944 /* write sections header */
945 if (a_Dpip_dsh_write_str(sh, 0, modifypage_sections_header))
946 return 1;
947 /* write sections */
948 for (i = 0; (sec_node = dList_nth_data(B_secs, i)); ++i) {
949 dStr_sprintf(dstr, modifypage_sections_item,
950 sec_node->section, sec_node->section, sec_node->title);
951 if (a_Dpip_dsh_write_str(sh, 0, dstr->str))
952 return 1;
953 }
954 /* write sections footer */
955 if (a_Dpip_dsh_write_str(sh, 0, modifypage_sections_footer))
956 return 1;
957
958 /* send page middle */
959 if (a_Dpip_dsh_write_str(sh, 0, modifypage_middle1))
960 return 1;
961
962 /* send bookmark cards */
963 for (i = 0; (sec_node = dList_nth_data(B_secs, i)); ++i) {
964 /* send card header */
965 l_title = make_one_line_str(sec_node->title);
966 dStr_sprintf(dstr, modifypage_section_card_header,
967 sec_node->section, l_title);
968 dFree(l_title);
969 if (a_Dpip_dsh_write_str(sh, 0, dstr->str))
970 return 1;
971
972 /* send section's bookmarks */
973 for (j = 0; (bm_node = dList_nth_data(B_bms, j)); ++j) {
974 if (bm_node->section == sec_node->section) {
975 dStr_sprintf(dstr, modifypage_section_card_item,
976 bm_node->key, bm_node->url, bm_node->title);
977 if (a_Dpip_dsh_write_str(sh, 0, dstr->str))
978 return 1;
979 }
980 }
981
982 /* send card footer */
983 if (a_Dpip_dsh_write_str(sh, 0, modifypage_section_card_footer))
984 return 1;
985 }
986
987 /* finish page */
988 if (a_Dpip_dsh_write_str(sh, 1, modifypage_footer))
989 return 1;
990
991 return 2;
992 }
993
994 /*
995 * Send the HTML for the modify page for "add section"
996 * Return code: { 0:OK, 1:Abort, 2:Close }
997 */
Bmsrv_send_modify_page_add_section(Dsh * sh)998 static int Bmsrv_send_modify_page_add_section(Dsh *sh)
999 {
1000 /* send modify page2 */
1001 if (a_Dpip_dsh_write_str(sh, 1, modifypage_add_section_page))
1002 return 1;
1003
1004 return 2;
1005 }
1006
1007 /*
1008 * Send the HTML for the modify page for "add url"
1009 * Return code: { 0:OK, 1:Abort, 2:Close }
1010 */
Bmsrv_send_modify_page_add_url(Dsh * sh)1011 static int Bmsrv_send_modify_page_add_url(Dsh *sh)
1012 {
1013 if (a_Dpip_dsh_write_str(sh, 1, modifypage_add_url))
1014 return 1;
1015 return 2;
1016 }
1017
1018 /*
1019 * Parse a modify urls request and either:
1020 * - make a local copy of the url
1021 * or
1022 * - send the modify page for the marked urls and sections
1023 * Return code: { 0:OK, 1:Abort, 2:Close }
1024 */
Bmsrv_send_modify_update(Dsh * sh,char * url)1025 static int Bmsrv_send_modify_update(Dsh *sh, char *url)
1026 {
1027 static char *url1 = NULL;
1028 static Dstr *dstr = NULL;
1029 char *p, *q;
1030 int i, key, n_sec, n_url;
1031 BmRec *bm_node;
1032 BmSec *sec_node;
1033
1034 /* bookmarks were loaded before */
1035
1036 if (!dstr)
1037 dstr = dStr_new("");
1038
1039 if (sh == NULL) {
1040 /* just copy url */
1041 dFree(url1);
1042 url1 = dStrdup(url);
1043 return 0;
1044 }
1045
1046 /* send HTML here */
1047 if (a_Dpip_dsh_write_str(sh, 0, modifypage_update_header))
1048 return 1;
1049
1050 /* Count number of marked urls and sections */
1051 Bmsrv_count_urls_and_sections(url1, &n_sec, &n_url);
1052
1053 if (n_sec) {
1054 dStr_sprintf(dstr, modifypage_update_title, "Update sections:");
1055 a_Dpip_dsh_write_str(sh, 0, dstr->str);
1056 a_Dpip_dsh_write_str(sh, 0, modifypage_update_item_header);
1057 /* send items here */
1058 p = strchr(url1, '?');
1059 for (q = p; (q = strstr(q, "&s")); ++q) {
1060 for (i = 0; isdigit(q[2+i]); ++i);
1061 if (q[2+i] == '=') {
1062 key = strtol(q + 2, NULL, 10);
1063 if ((sec_node = Bms_get_sec(key))) {
1064 dStr_sprintf(dstr, modifypage_update_item2,
1065 sec_node->section, sec_node->title);
1066 a_Dpip_dsh_write_str(sh, 0, dstr->str);
1067 }
1068 }
1069 }
1070 a_Dpip_dsh_write_str(sh, 0, modifypage_update_item_footer);
1071 }
1072
1073 if (n_url) {
1074 dStr_sprintf(dstr, modifypage_update_title, "Update titles:");
1075 a_Dpip_dsh_write_str(sh, 0, dstr->str);
1076 a_Dpip_dsh_write_str(sh, 0, modifypage_update_item_header);
1077 /* send items here */
1078 p = strchr(url1, '?');
1079 for (q = p; (q = strstr(q, "&url")); ++q) {
1080 for (i = 0; isdigit(q[4+i]); ++i);
1081 if (q[4+i] == '=') {
1082 key = strtol(q + 4, NULL, 10);
1083 bm_node = Bms_get(key);
1084 dStr_sprintf(dstr, modifypage_update_item,
1085 bm_node->key, bm_node->title, bm_node->url);
1086 a_Dpip_dsh_write_str(sh, 0, dstr->str);
1087 }
1088 }
1089 a_Dpip_dsh_write_str(sh, 0, modifypage_update_item_footer);
1090 }
1091
1092 a_Dpip_dsh_write_str(sh, 1, modifypage_update_footer);
1093
1094 return 2;
1095 }
1096
1097 /*
1098 * Make the modify-page and send it back
1099 * Return code: { 0:OK, 1:Abort, 2:Close }
1100 */
Bmsrv_send_modify_answer(Dsh * sh,char * url)1101 static int Bmsrv_send_modify_answer(Dsh *sh, char *url)
1102 {
1103 char *d_cmd;
1104 int st;
1105
1106 d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", url);
1107 st = a_Dpip_dsh_write_str(sh, 1, d_cmd);
1108 dFree(d_cmd);
1109 if (st != 0)
1110 return 1;
1111
1112 /* Send HTTP header */
1113 if (a_Dpip_dsh_write_str(sh, 0, Header) != 0) {
1114 return 1;
1115 }
1116
1117 if (MODIFY_PAGE_NUM == 2) {
1118 MODIFY_PAGE_NUM = 1;
1119 return Bmsrv_send_modify_page_add_section(sh);
1120 } else if (MODIFY_PAGE_NUM == 3) {
1121 MODIFY_PAGE_NUM = 1;
1122 return Bmsrv_send_modify_update(sh, NULL);
1123 } else if (MODIFY_PAGE_NUM == 4) {
1124 MODIFY_PAGE_NUM = 1;
1125 return Bmsrv_send_modify_page_add_url(sh);
1126 } else {
1127 return Bmsrv_send_modify_page(sh);
1128 }
1129 }
1130
1131
1132 /* Operations */
1133
1134 /*
1135 * Parse a delete bms request, delete them, and update bm file.
1136 * Return code: { 0:OK, 1:Abort }
1137 */
Bmsrv_modify_delete(char * url)1138 static int Bmsrv_modify_delete(char *url)
1139 {
1140 char *p;
1141 int nb, ns, key;
1142
1143 /* bookmarks were loaded before */
1144
1145 /* Remove marked sections */
1146 p = strchr(url, '?');
1147 for (ns = 0; (p = strstr(p, "&s")); ++p) {
1148 if (isdigit(p[2])) {
1149 key = strtol(p + 2, NULL, 10);
1150 Bms_sec_del(key);
1151 ++ns;
1152 }
1153 }
1154
1155 /* Remove marked urls */
1156 p = strchr(url, '?');
1157 for (nb = 0; (p = strstr(p, "&url")); ++p) {
1158 if (isdigit(p[4])) {
1159 key = strtol(p + 4, NULL, 10);
1160 Bms_del(key);
1161 ++nb;
1162 }
1163 }
1164
1165 /* -- This doesn't work because dillo erases the message upon the
1166 * receipt of the first data stream.
1167 *
1168 sprintf(msg, "Deleted %d bookmark%s!>", n, (n > 1) ? "s" : "");
1169 if (Bmsrv_dpi_send_status_msg(sh, msg))
1170 return 1;
1171 */
1172
1173 /* Write new bookmarks file */
1174 if (nb || ns)
1175 Bms_save();
1176
1177 return 0;
1178 }
1179
1180 /*
1181 * Parse a move urls request, move and update bm file.
1182 * Return code: { 0:OK, 1:Abort }
1183 */
Bmsrv_modify_move(char * url)1184 static int Bmsrv_modify_move(char *url)
1185 {
1186 char *p;
1187 int n, section = 0, key;
1188
1189 /* bookmarks were loaded before */
1190
1191 /* get target section */
1192 for (p = url; (p = strstr(p, "&s")); ++p) {
1193 if (isdigit(p[2])) {
1194 section = strtol(p + 2, NULL, 10);
1195 break;
1196 }
1197 }
1198 if (!p)
1199 return 1;
1200
1201 /* move marked urls */
1202 p = strchr(url, '?');
1203 for (n = 0; (p = strstr(p, "&url")); ++p) {
1204 if (isdigit(p[4])) {
1205 key = strtol(p + 4, NULL, 10);
1206 Bms_move(key, section);
1207 ++n;
1208 }
1209 }
1210
1211 /* Write new bookmarks file */
1212 if (n) {
1213 Bms_save();
1214 }
1215
1216 return 0;
1217 }
1218
1219 /*
1220 * Parse a modify request: update urls and sections, then save.
1221 * Return code: { 0:OK, 1:Abort }
1222 */
Bmsrv_modify_update(char * url)1223 static int Bmsrv_modify_update(char *url)
1224 {
1225 char *p, *q, *title;
1226 int i, key;
1227
1228 /* bookmarks were loaded before */
1229
1230 p = strchr(url, '?');
1231 for ( ; (p = strstr(p, "s")); ++p) {
1232 if (p[-1] == '&' || p[-1] == '?' ) {
1233 for (i = 0; isdigit(p[1 + i]); ++i);
1234 if (i && p[1 + i] == '=') {
1235 /* we have a title/key to change */
1236 key = strtol(p + 1, NULL, 10);
1237 if ((q = strchr(p + 1, '&')))
1238 title = dStrndup(p + 2 + i, (uint_t)(q - (p + 2 + i)));
1239 else
1240 title = dStrdup(p + 2 + i);
1241
1242 Unencode_str(title);
1243 Bms_update_sec_title(key, title);
1244 dFree(title);
1245 }
1246 }
1247 }
1248
1249 p = strchr(url, '?');
1250 for ( ; (p = strstr(p, "title")); ++p) {
1251 if (p[-1] == '&' || p[-1] == '?' ) {
1252 for (i = 0; isdigit(p[5 + i]); ++i);
1253 if (i && p[5 + i] == '=') {
1254 /* we have a title/key to change */
1255 key = strtol(p + 5, NULL, 10);
1256 if ((q = strchr(p + 5, '&')))
1257 title = dStrndup(p + 6 + i, (uint_t)(q - (p + 6 + i)));
1258 else
1259 title = dStrdup(p + 6 + i);
1260
1261 Unencode_str(title);
1262 Bms_update_title(key, title);
1263 dFree(title);
1264 }
1265 }
1266 }
1267
1268 /* Write new bookmarks file */
1269 Bms_save();
1270
1271 return 0;
1272 }
1273
1274 /*
1275 * Parse an "add section" request, and update the bm file.
1276 * Return code: { 0:OK, 1:Abort }
1277 */
Bmsrv_modify_add_section(char * url)1278 static int Bmsrv_modify_add_section(char *url)
1279 {
1280 char *p, *title = NULL;
1281
1282 /* bookmarks were loaded before */
1283
1284 /* get new section's title */
1285 if ((p = strstr(url, "&title="))) {
1286 title = dStrdup (p + 7);
1287 if ((p = strchr(title, '&')))
1288 *p = 0;
1289 Unencode_str(title);
1290 } else
1291 return 1;
1292
1293 Bms_sec_add(title);
1294 dFree(title);
1295
1296 /* Write new bookmarks file */
1297 Bms_save();
1298
1299 return 0;
1300 }
1301
1302 /*
1303 * Parse an "add url" request, and update the bm file.
1304 * Return code: { 0:OK, 1:Abort }
1305 */
Bmsrv_modify_add_url(Dsh * sh,char * s_url)1306 static int Bmsrv_modify_add_url(Dsh *sh, char *s_url)
1307 {
1308 char *p, *q, *title, *u_title, *url;
1309 int i;
1310 static int section = 0;
1311
1312 /* bookmarks were loaded before */
1313
1314 if (sh == NULL) {
1315 /* look for section */
1316 for (q = s_url; (q = strstr(q, "&s")); ++q) {
1317 for (i = 0; isdigit(q[2+i]); ++i);
1318 if (q[2+i] == '=')
1319 section = strtol(q + 2, NULL, 10);
1320 }
1321 return 1;
1322 }
1323
1324 if (!(p = strstr(s_url, "&title=")) ||
1325 !(q = strstr(s_url, "&url=")))
1326 return 1;
1327
1328 title = dStrdup (p + 7);
1329 if ((p = strchr(title, '&')))
1330 *p = 0;
1331 url = dStrdup (q + 5);
1332 if ((p = strchr(url, '&')))
1333 *p = 0;
1334 if (strlen(title) && strlen(url)) {
1335 Unencode_str(title);
1336 Unencode_str(url);
1337 u_title = Unescape_html_str(title);
1338 Bms_add(section, url, u_title);
1339 dFree(u_title);
1340 }
1341 dFree(title);
1342 dFree(url);
1343 section = 0;
1344
1345 /* TODO: we should send an "Bookmark added" message, but the
1346 msg-after-HTML functionallity is still pending, not hard though. */
1347
1348 /* Write new bookmarks file */
1349 Bms_save();
1350
1351 return 0;
1352 }
1353
1354 /*
1355 * Check the parameters of a modify request, and return an error message
1356 * when it's wrong.
1357 * Return code: { 0:OK, 2:Close }
1358 */
Bmsrv_check_modify_request(Dsh * sh,char * url)1359 static int Bmsrv_check_modify_request(Dsh *sh, char *url)
1360 {
1361 char *p, *msg;
1362 int n_sec, n_url;
1363
1364 /* Count number of marked urls and sections */
1365 Bmsrv_count_urls_and_sections(url, &n_sec, &n_url);
1366
1367 p = strchr(url, '?');
1368 if (strstr(p, "operation=delete&")) {
1369 if (n_url || n_sec)
1370 return 0;
1371 msg = "Delete: you must mark what to delete!";
1372
1373 } else if (strstr(url, "operation=move&")) {
1374 if (n_url && n_sec)
1375 return 0;
1376 else if (n_url)
1377 msg = "Move: you must mark a target section!";
1378 else if (n_sec)
1379 msg = "Move: can not move a section (yet).";
1380 else
1381 msg = "Move: you must mark some urls, and a target section!";
1382
1383 } else if (strstr(url, "operation=modify&")) {
1384 if (n_url || n_sec)
1385 return 0;
1386 msg = "Modify: you must mark what to update!";
1387
1388 } else if (strstr(url, "operation=modify2&")) {
1389 /* nothing to check here */
1390 return 0;
1391
1392 } else if (strstr(url, "operation=add_sec&")) {
1393 /* nothing to check here */
1394 return 0;
1395
1396 } else if (strstr(url, "operation=add_section&")) {
1397 /* nothing to check here */
1398 return 0;
1399
1400 } else if (strstr(url, "operation=add_url&")) {
1401 if (n_sec <= 1)
1402 return 0;
1403 msg = "Add url: only one target section is allowed!";
1404
1405 } else if (strstr(url, "operation=add_url2&")) {
1406 /* nothing to check here */
1407 return 0;
1408
1409 } else if (strstr(url, "operation=none&")) {
1410 msg = "No operation, just do nothing!";
1411
1412 } else {
1413 msg = "Sorry, not implemented yet.";
1414 }
1415
1416 Bmsrv_dpi_send_status_msg(sh, msg);
1417 return 2;
1418 }
1419
1420 /*
1421 * Parse a and process a modify request.
1422 * Return code: { 0:OK, 1:Abort, 2:Close }
1423 */
Bmsrv_process_modify_request(Dsh * sh,char * url)1424 static int Bmsrv_process_modify_request(Dsh *sh, char *url)
1425 {
1426 /* check the provided parameters */
1427 if (Bmsrv_check_modify_request(sh, url) != 0)
1428 return 2;
1429
1430 if (strstr(url, "operation=delete&")) {
1431 if (Bmsrv_modify_delete(url) == 1)
1432 return 1;
1433 if (Bmsrv_send_reload_request(sh, "dpi:/bm/modify") == 1)
1434 return 1;
1435
1436 } else if (strstr(url, "operation=move&")) {
1437 if (Bmsrv_modify_move(url) == 1)
1438 return 1;
1439 if (Bmsrv_send_reload_request(sh, "dpi:/bm/modify") == 1)
1440 return 1;
1441
1442 } else if (strstr(url, "operation=modify&")) {
1443 /* make a local copy of 'url' */
1444 Bmsrv_send_modify_update(NULL, url);
1445 MODIFY_PAGE_NUM = 3;
1446 if (Bmsrv_send_reload_request(sh, "dpi:/bm/modify") == 1)
1447 return 1;
1448
1449 } else if (strstr(url, "operation=modify2&")) {
1450 if (Bmsrv_modify_update(url) == 1)
1451 return 1;
1452 if (Bmsrv_send_reload_request(sh, "dpi:/bm/modify") == 1)
1453 return 1;
1454
1455 } else if (strstr(url, "operation=add_sec&")) {
1456 /* this global variable tells which page to send (--hackish...) */
1457 MODIFY_PAGE_NUM = 2;
1458 if (Bmsrv_send_reload_request(sh, "dpi:/bm/modify") == 1)
1459 return 1;
1460
1461 } else if (strstr(url, "operation=add_section&")) {
1462 if (Bmsrv_modify_add_section(url) == 1)
1463 return 1;
1464 if (Bmsrv_send_reload_request(sh, "dpi:/bm/modify") == 1)
1465 return 1;
1466
1467 } else if (strstr(url, "operation=add_url&")) {
1468 /* this global variable tells which page to send (--hackish...) */
1469 MODIFY_PAGE_NUM = 4;
1470 /* parse section if present */
1471 Bmsrv_modify_add_url(NULL, url);
1472 if (Bmsrv_send_reload_request(sh, "dpi:/bm/modify") == 1)
1473 return 1;
1474
1475 } else if (strstr(url, "operation=add_url2&")) {
1476 if (Bmsrv_modify_add_url(sh, url) == 1)
1477 return 1;
1478 if (Bmsrv_send_reload_request(sh, "dpi:/bm/modify") == 1)
1479 return 1;
1480 }
1481
1482 return 2;
1483 }
1484
1485 /* -- Bookmarks ------------------------------------------------------------ */
1486
1487 /*
1488 * Send the current bookmarks page (in HTML)
1489 */
send_bm_page(Dsh * sh)1490 static int send_bm_page(Dsh *sh)
1491 {
1492 static Dstr *dstr = NULL;
1493 char *l_title;
1494 BmSec *sec_node;
1495 BmRec *bm_node;
1496 int i, j;
1497
1498 if (!dstr)
1499 dstr = dStr_new("");
1500
1501 if (a_Dpip_dsh_write_str(sh, 0, mainpage_header))
1502 return 1;
1503
1504 /* write sections header */
1505 if (a_Dpip_dsh_write_str(sh, 0, mainpage_sections_header))
1506 return 1;
1507 /* write sections */
1508 for (i = 0; (sec_node = dList_nth_data(B_secs, i)); ++i) {
1509 dStr_sprintf(dstr, mainpage_sections_item,
1510 sec_node->section, sec_node->title);
1511 if (a_Dpip_dsh_write_str(sh, 0, dstr->str))
1512 return 1;
1513 }
1514 /* write sections footer */
1515 if (a_Dpip_dsh_write_str(sh, 0, mainpage_sections_footer))
1516 return 1;
1517
1518 /* send page middle */
1519 if (a_Dpip_dsh_write_str(sh, 0, mainpage_middle1))
1520 return 1;
1521
1522 /* send bookmark cards */
1523 for (i = 0; (sec_node = dList_nth_data(B_secs, i)); ++i) {
1524 /* send card header */
1525 l_title = make_one_line_str(sec_node->title);
1526 dStr_sprintf(dstr, mainpage_section_card_header,
1527 sec_node->section, l_title);
1528 dFree(l_title);
1529 if (a_Dpip_dsh_write_str(sh, 0, dstr->str))
1530 return 1;
1531
1532 /* send section's bookmarks */
1533 for (j = 0; (bm_node = dList_nth_data(B_bms, j)); ++j) {
1534 if (bm_node->section == sec_node->section) {
1535 dStr_sprintf(dstr, mainpage_section_card_item,
1536 bm_node->url, bm_node->title);
1537 if (a_Dpip_dsh_write_str(sh, 0, dstr->str))
1538 return 1;
1539 }
1540 }
1541
1542 /* send card footer */
1543 if (a_Dpip_dsh_write_str(sh, 0, mainpage_section_card_footer))
1544 return 1;
1545 }
1546
1547 /* finish page */
1548 if (a_Dpip_dsh_write_str(sh, 1, mainpage_footer))
1549 return 1;
1550
1551 return 0;
1552 }
1553
1554
1555 /* -- Dpi parser ----------------------------------------------------------- */
1556
1557 /*
1558 * Parse a data stream (dpi protocol)
1559 * Note: Buf is a dpip token (zero terminated string)
1560 * Return code: { 0:OK, 1:Abort, 2:Close }
1561 */
Bmsrv_parse_token(Dsh * sh,char * Buf)1562 static int Bmsrv_parse_token(Dsh *sh, char *Buf)
1563 {
1564 static char *msg1=NULL, *msg2=NULL, *msg3=NULL;
1565 char *cmd, *d_cmd, *url, *title, *msg;
1566 size_t BufSize;
1567 int st;
1568
1569 if (!msg1) {
1570 /* Initialize data for the "chat" command. */
1571 msg1 = a_Dpip_build_cmd("cmd=%s msg=%s", "chat", "Hi browser");
1572 msg2 = a_Dpip_build_cmd("cmd=%s msg=%s", "chat", "Is it worth?");
1573 msg3 = a_Dpip_build_cmd("cmd=%s msg=%s", "chat", "Ok, send it");
1574 }
1575
1576 if (sh->mode & DPIP_RAW) {
1577 MSG("ERROR: Unhandled DPIP_RAW mode!\n");
1578 return 1;
1579 }
1580
1581 BufSize = strlen(Buf);
1582 cmd = a_Dpip_get_attr_l(Buf, BufSize, "cmd");
1583
1584 if (cmd && strcmp(cmd, "chat") == 0) {
1585 dFree(cmd);
1586 msg = a_Dpip_get_attr_l(Buf, BufSize, "msg");
1587 if (*msg == 'H') {
1588 /* "Hi server" */
1589 if (a_Dpip_dsh_write_str(sh, 1, msg1))
1590 return 1;
1591 } else if (*msg == 'I') {
1592 /* "I want to set abookmark" */
1593 if (a_Dpip_dsh_write_str(sh, 1, msg2))
1594 return 1;
1595 } else if (*msg == 'S') {
1596 /* "Sure" */
1597 if (a_Dpip_dsh_write_str(sh, 1, msg3))
1598 return 1;
1599 }
1600 dFree(msg);
1601 return 0;
1602 }
1603
1604 /* sync with the bookmarks file */
1605 Bms_cond_load();
1606
1607 if (cmd && strcmp(cmd, "DpiBye") == 0) {
1608 MSG("(pid %d): Got DpiBye.\n", (int)getpid());
1609 exit(0);
1610
1611 } else if (cmd && strcmp(cmd, "add_bookmark") == 0) {
1612 dFree(cmd);
1613 url = a_Dpip_get_attr_l(Buf, BufSize, "url");
1614 title = a_Dpip_get_attr_l(Buf, BufSize, "title");
1615 if (strlen(title) == 0) {
1616 dFree(title);
1617 title = dStrdup("(Untitled)");
1618 }
1619 if (url && title)
1620 Bmsrv_add_bm(sh, url, title);
1621 dFree(url);
1622 dFree(title);
1623 return 2;
1624
1625 } else if (cmd && strcmp(cmd, "open_url") == 0) {
1626 dFree(cmd);
1627 url = a_Dpip_get_attr_l(Buf, BufSize, "url");
1628
1629 if (dStrnAsciiCasecmp(url, "dpi:", 4) == 0) {
1630 if (strcmp(url+4, "/bm/modify") == 0) {
1631 st = Bmsrv_send_modify_answer(sh, url);
1632 dFree(url);
1633 return st;
1634 } else if (strncmp(url+4, "/bm/modify?", 11) == 0) {
1635 /* process request */
1636 st = Bmsrv_process_modify_request(sh, url);
1637 dFree(url);
1638 return st;
1639 }
1640 }
1641
1642
1643 d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", url);
1644 dFree(url);
1645 st = a_Dpip_dsh_write_str(sh, 1, d_cmd);
1646 dFree(d_cmd);
1647 if (st != 0)
1648 return 1;
1649
1650 /* Send HTTP header */
1651 if (a_Dpip_dsh_write_str(sh, 1, Header) != 0) {
1652 return 1;
1653 }
1654
1655 st = send_bm_page(sh);
1656 if (st != 0) {
1657 char *err =
1658 DOCTYPE
1659 "<HTML><body id='dillo_bm'> Error on the bookmarks server..."
1660 " </body></html>";
1661 if (a_Dpip_dsh_write_str(sh, 1, err) != 0) {
1662 return 1;
1663 }
1664 }
1665 return 2;
1666 }
1667
1668 return 0;
1669 }
1670
1671 /* -- Termination handlers ----------------------------------------------- */
1672 /*
1673 * (was to delete the local namespace socket),
1674 * but this is handled by 'dpid' now.
1675 */
cleanup(void)1676 static void cleanup(void)
1677 {
1678 /* no cleanup required */
1679 }
1680
1681 /*
1682 * Perform any necessary cleanups upon abnormal termination
1683 */
termination_handler(int signum)1684 static void termination_handler(int signum)
1685 {
1686 exit(signum);
1687 }
1688
1689
1690 /*
1691 * -- MAIN -------------------------------------------------------------------
1692 */
main(void)1693 int main(void) {
1694 struct sockaddr_un spun;
1695 int sock_fd, code;
1696 socklen_t address_size;
1697 char *tok;
1698 Dsh *sh;
1699
1700 /* Arrange the cleanup function for terminations via exit() */
1701 atexit(cleanup);
1702
1703 /* Arrange the cleanup function for abnormal terminations */
1704 if (signal (SIGINT, termination_handler) == SIG_IGN)
1705 signal (SIGINT, SIG_IGN);
1706 if (signal (SIGHUP, termination_handler) == SIG_IGN)
1707 signal (SIGHUP, SIG_IGN);
1708 if (signal (SIGTERM, termination_handler) == SIG_IGN)
1709 signal (SIGTERM, SIG_IGN);
1710
1711 /* We may receive SIGPIPE (e.g. socket is closed early by our client) */
1712 signal(SIGPIPE, SIG_IGN);
1713
1714 /* Initialize local data */
1715 B_bms = dList_new(512);
1716 B_secs = dList_new(32);
1717 BmFile = dStrconcat(dGethomedir(), "/.dillo/bm.txt", NULL);
1718 /* some OSes may need this... */
1719 address_size = sizeof(struct sockaddr_un);
1720
1721 MSG("(v.13): accepting connections...\n");
1722
1723 while (1) {
1724 sock_fd = accept(STDIN_FILENO, (struct sockaddr *)&spun, &address_size);
1725 if (sock_fd == -1) {
1726 perror("[accept]");
1727 exit(1);
1728 }
1729
1730 /* create the Dsh structure */
1731 sh = a_Dpip_dsh_new(sock_fd, sock_fd, 8*1024);
1732
1733 /* Authenticate our client... */
1734 if (!(tok = a_Dpip_dsh_read_token(sh, 1)) ||
1735 a_Dpip_check_auth(tok) < 0) {
1736 MSG("can't authenticate request: %s\n", dStrerror(errno));
1737 a_Dpip_dsh_close(sh);
1738 exit(1);
1739 }
1740 dFree(tok);
1741
1742 while (1) {
1743 code = 1;
1744 if ((tok = a_Dpip_dsh_read_token(sh, 1)) != NULL) {
1745 /* Let's see what we fished... */
1746 code = Bmsrv_parse_token(sh, tok);
1747 }
1748 dFree(tok);
1749
1750 if (code != 0) {
1751 /* socket is not operative (e.g. closed by client) */
1752 break;
1753 }
1754 }
1755
1756 a_Dpip_dsh_close(sh);
1757 a_Dpip_dsh_free(sh);
1758
1759 }/*while*/
1760 }
1761