dillo  3.0.5
About: dillo is a small, fast, extensible Web browser particularly suitable for older or smaller computers and embedded systems (but only limited or no support for frames, CSS, JavaScript, Java).
  Fossies Dox: dillo-3.0.5.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

bookmarks.c
Go to the documentation of this file.
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 " &nbsp;&nbsp;&nbsp;%s&nbsp;&nbsp;&nbsp;</b></font></td>\n"
199 " <td bgcolor='white' width='100%%'>&nbsp;</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 " &nbsp;&nbsp;&nbsp;%s&nbsp;&nbsp;&nbsp;</b></font></td>\n"
207 " <td bgcolor='white' width='100%%'>&nbsp;</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&nbsp;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&nbsp;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 &nbsp;
408  */
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, "&nbsp;");
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  */
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  */
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  */
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  */
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  */
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  */
502 static BmRec *Bms_get(int key)
503 {
505 }
506 
507 /*
508  * Return the Section record by key
509  */
510 static BmSec *Bms_get_sec(int key)
511 {
513 }
514 
515 /*
516  * Add a bookmark
517  */
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  */
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  */
546 static void Bms_del(int key)
547 {
548  BmRec *bm_node;
549 
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  */
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),
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),
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  */
589 static void Bms_move(int key, int target_section)
590 {
591  BmRec *bm_node;
592 
594  if (bm_node) {
595  bm_node->section = target_section;
596  }
597 }
598 
599 /*
600  * Update a bookmark title by key
601  */
602 static void Bms_update_title(int key, char *n_title)
603 {
604  BmRec *bm_node;
605 
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  */
616 static void Bms_update_sec_title(int key, char *n_title)
617 {
618  BmSec *sec_node;
619 
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  */
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  */
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  */
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  */
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  */
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... */
786  if (stat(BmFile, &TimeStamp) != 0)
787  TimeStamp.st_mtime = 0;
788  }
789 
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  */
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  */
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  */
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  */
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  */
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 */
942  return 1;
943 
944  /* write sections header */
946  return 1;
947  /* write sections */
948  for (i = 0; (sec_node = dList_nth_data(B_secs, i)); ++i) {
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 */
956  return 1;
957 
958  /* send page middle */
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);
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) {
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 */
984  return 1;
985  }
986 
987  /* finish page */
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  */
999 {
1000  /* send modify page2 */
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  */
1012 {
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  */
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 */
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&nbsp;sections:");
1055  a_Dpip_dsh_write_str(sh, 0, dstr->str);
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))) {
1065  sec_node->section, sec_node->title);
1066  a_Dpip_dsh_write_str(sh, 0, dstr->str);
1067  }
1068  }
1069  }
1071  }
1072 
1073  if (n_url) {
1074  dStr_sprintf(dstr, modifypage_update_title, "Update&nbsp;titles:");
1075  a_Dpip_dsh_write_str(sh, 0, dstr->str);
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);
1085  bm_node->key, bm_node->title, bm_node->url);
1086  a_Dpip_dsh_write_str(sh, 0, dstr->str);
1087  }
1088  }
1090  }
1091 
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  */
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;
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;
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  */
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  */
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  */
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  */
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  */
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  */
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 
1417  return 2;
1418 }
1419 
1420 /*
1421  * Parse a and process a modify request.
1422  * Return code: { 0:OK, 1:Abort, 2:Close }
1423  */
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  */
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 
1502  return 1;
1503 
1504  /* write sections header */
1506  return 1;
1507  /* write sections */
1508  for (i = 0; (sec_node = dList_nth_data(B_secs, i)); ++i) {
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 */
1516  return 1;
1517 
1518  /* send page middle */
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);
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) {
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 */
1544  return 1;
1545  }
1546 
1547  /* finish page */
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  */
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  */
1676 static void cleanup(void)
1677 {
1678  /* no cleanup required */
1679 }
1680 
1681 /*
1682  * Perform any necessary cleanups upon abnormal termination
1683  */
1684 static void termination_handler(int signum)
1685 {
1686  exit(signum);
1687 }
1688 
1689 
1690 /*
1691  * -- MAIN -------------------------------------------------------------------
1692  */
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));
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 
1758 
1759  }/*while*/
1760 }
main
int main(void)
Definition: bookmarks.c:1693
dStr_free
void dStr_free(Dstr *ds, int all)
Definition: dlib.c:335
a_Dpip_dsh_new
Dsh * a_Dpip_dsh_new(int fd_in, int fd_out, int flush_sz)
Definition: dpip.c:242
BmRec::key
int key
Definition: bookmarks.c:57
TRUE
#define TRUE
Definition: dlib.h:23
MSG
#define MSG(...)
Definition: bookmarks.c:45
Bms_get_sec
static BmSec * Bms_get_sec(int key)
Definition: bookmarks.c:510
mainpage_middle1
static const char * mainpage_middle1
Definition: bookmarks.c:185
VOIDP2INT
#define VOIDP2INT(p)
Definition: dlib.h:43
mainpage_section_card_footer
static const char * mainpage_section_card_footer
Definition: bookmarks.c:218
sh
static Dsh * sh
Definition: datauri.c:38
modifypage_update_item2
static const char * modifypage_update_item2
Definition: bookmarks.c:334
modifypage_add_section_page
static const char * modifypage_add_section_page
Definition: bookmarks.c:242
cleanup
static void cleanup(void)
Definition: bookmarks.c:1676
dFree
void dFree(void *mem)
Definition: dlib.c:66
Dsh
Definition: dpip.h:31
dList_length
int dList_length(Dlist *lp)
Definition: dlib.c:611
modifypage_sections_header
static const char * modifypage_sections_header
Definition: bookmarks.c:159
dStrconcat
char * dStrconcat(const char *s1,...)
Definition: dlib.c:100
BmFileTimeStamp
static time_t BmFileTimeStamp
Definition: bookmarks.c:76
Bmsrv_send_modify_page
static int Bmsrv_send_modify_page(Dsh *sh)
Definition: bookmarks.c:929
Bmsrv_check_modify_request
static int Bmsrv_check_modify_request(Dsh *sh, char *url)
Definition: bookmarks.c:1359
Bms_node_by_section_cmp
static int Bms_node_by_section_cmp(const void *node, const void *key)
Definition: bookmarks.c:486
Bmsrv_modify_add_url
static int Bmsrv_modify_add_url(Dsh *sh, char *s_url)
Definition: bookmarks.c:1306
dStrerror
#define dStrerror
Definition: dlib.h:95
modifypage_header
static const char * modifypage_header
Definition: bookmarks.c:112
modifypage_section_card_header
static const char * modifypage_section_card_header
Definition: bookmarks.c:201
Dstr::str
char * str
Definition: dlib.h:105
key
Definition: colors.c:28
Escape_uri_str
char * Escape_uri_str(const char *str, const char *p_esc_set)
Definition: dpiutil.c:36
modifypage_update_item
static const char * modifypage_update_item
Definition: bookmarks.c:321
modifypage_middle1
static const char * modifypage_middle1
Definition: bookmarks.c:189
dList_nth_data
void * dList_nth_data(Dlist *lp, int n0)
Definition: dlib.c:660
Bms_cond_load
static int Bms_cond_load(void)
Definition: bookmarks.c:778
mainpage_section_card_item
static const char * mainpage_section_card_item
Definition: bookmarks.c:209
mainpage_sections_footer
static const char * mainpage_sections_footer
Definition: bookmarks.c:179
dList_find_custom
void * dList_find_custom(Dlist *lp, const void *data, dCompareFunc func)
Definition: dlib.c:702
Escape_html_str
char * Escape_html_str(const char *str)
Definition: dpiutil.c:93
BmFile
static char * BmFile
Definition: bookmarks.c:75
dNew
#define dNew(type, count)
Definition: dlib.h:49
dStrndup
char * dStrndup(const char *s, size_t sz)
Definition: dlib.c:86
Bmsrv_send_modify_update
static int Bmsrv_send_modify_update(Dsh *sh, char *url)
Definition: bookmarks.c:1025
a_Dpip_dsh_read_token
char * a_Dpip_dsh_read_token(Dsh *dsh, int blocking)
Definition: dpip.c:488
Bmsrv_count_urls_and_sections
static void Bmsrv_count_urls_and_sections(char *url, int *n_sec, int *n_url)
Definition: bookmarks.c:891
Bms_check_import
static void Bms_check_import(void)
Definition: bookmarks.c:681
Bmsrv_parse_token
static int Bmsrv_parse_token(Dsh *sh, char *Buf)
Definition: bookmarks.c:1562
modifypage_update_item_footer
static const char * modifypage_update_item_footer
Definition: bookmarks.c:344
bm_key
static int bm_key
Definition: bookmarks.c:78
mainpage_footer
static const char * mainpage_footer
Definition: bookmarks.c:226
a_Dpip_check_auth
int a_Dpip_check_auth(const char *auth_tag)
Definition: dpip.c:196
Bms_node_by_key_cmp
static int Bms_node_by_key_cmp(const void *node, const void *key)
Definition: bookmarks.c:478
dStr_new
Dstr * dStr_new(const char *s)
Definition: dlib.c:323
Dsh::mode
int mode
Definition: dpip.h:41
Bms_del
static void Bms_del(int key)
Definition: bookmarks.c:546
Bmsrv_modify_delete
static int Bmsrv_modify_delete(char *url)
Definition: bookmarks.c:1138
BmRec::section
int section
Definition: bookmarks.c:58
Unencode_str
static void Unencode_str(char *e_str)
Definition: bookmarks.c:437
Bmsrv_send_reload_request
static int Bmsrv_send_reload_request(Dsh *sh, char *url)
Definition: bookmarks.c:914
modifypage_section_card_item
static const char * modifypage_section_card_item
Definition: bookmarks.c:213
Bmsrv_send_modify_page_add_section
static int Bmsrv_send_modify_page_add_section(Dsh *sh)
Definition: bookmarks.c:998
modifypage_update_item_header
static const char * modifypage_update_item_header
Definition: bookmarks.c:318
Bmsrv_send_modify_page_add_url
static int Bmsrv_send_modify_page_add_url(Dsh *sh)
Definition: bookmarks.c:1011
Bms_get
static BmRec * Bms_get(int key)
Definition: bookmarks.c:502
mainpage_section_card_header
static const char * mainpage_section_card_header
Definition: bookmarks.c:193
Bmsrv_process_modify_request
static int Bmsrv_process_modify_request(Dsh *sh, char *url)
Definition: bookmarks.c:1424
modifypage_section_card_footer
static const char * modifypage_section_card_footer
Definition: bookmarks.c:222
Bmsrv_modify_update
static int Bmsrv_modify_update(char *url)
Definition: bookmarks.c:1223
B_bms
static Dlist * B_bms
Definition: bookmarks.c:77
DOCTYPE
#define DOCTYPE
Definition: bookmarks.c:47
a_Dpip_build_cmd
char * a_Dpip_build_cmd(const char *format,...)
Definition: dpip.c:78
dGetline
char * dGetline(FILE *stream)
Definition: dlib.c:926
Dstr::len
int len
Definition: dlib.h:104
Bmsrv_modify_move
static int Bmsrv_modify_move(char *url)
Definition: bookmarks.c:1184
a_Dpip_dsh_free
void a_Dpip_dsh_free(Dsh *dsh)
Definition: dpip.c:520
modifypage_update_footer
static const char * modifypage_update_footer
Definition: bookmarks.c:347
modifypage_update_header
static const char * modifypage_update_header
Definition: bookmarks.c:289
B_secs
static Dlist * B_secs
Definition: bookmarks.c:80
dGethomedir
char * dGethomedir()
Definition: dlib.c:904
Bms_free
static void Bms_free(void)
Definition: bookmarks.c:630
Bms_sec_del
static void Bms_sec_del(int section)
Definition: bookmarks.c:564
Bms_update_sec_title
static void Bms_update_sec_title(int key, char *n_title)
Definition: bookmarks.c:616
Dstr
Definition: dlib.h:102
sec_key
static int sec_key
Definition: bookmarks.c:81
BmRec
Definition: bookmarks.c:56
BmSec
Definition: bookmarks.c:63
send_bm_page
static int send_bm_page(Dsh *sh)
Definition: bookmarks.c:1490
BmSec::o_sec
int o_sec
Definition: bookmarks.c:67
dpiutil.h
Bms_move
static void Bms_move(int key, int target_section)
Definition: bookmarks.c:589
dList_append
void dList_append(Dlist *lp, void *data)
Definition: dlib.c:595
Unescape_html_str
char * Unescape_html_str(const char *str)
Definition: dpiutil.c:115
Bms_add
static void Bms_add(int section, char *url, char *title)
Definition: bookmarks.c:518
Bms_sec_add
static void Bms_sec_add(char *title)
Definition: bookmarks.c:533
dStr_sprintf
void dStr_sprintf(Dstr *ds, const char *format,...)
Definition: dlib.c:448
Bms_save
static int Bms_save(void)
Definition: bookmarks.c:804
Bms_sec_by_number_cmp
static int Bms_sec_by_number_cmp(const void *node, const void *key)
Definition: bookmarks.c:494
Bmsrv_send_modify_answer
static int Bmsrv_send_modify_answer(Dsh *sh, char *url)
Definition: bookmarks.c:1101
Bmsrv_dpi_send_status_msg
static int Bmsrv_dpi_send_status_msg(Dsh *sh, char *str)
Definition: bookmarks.c:463
a_Dpip_get_attr_l
char * a_Dpip_get_attr_l(const char *tag, size_t tagsize, const char *attrname)
Definition: dpip.c:129
Dlist
Definition: dlib.h:131
Bmsrv_add_bm
static int Bmsrv_add_bm(Dsh *sh, char *url, char *title)
Definition: bookmarks.c:866
Bms_normalize
static void Bms_normalize(void)
Definition: bookmarks.c:648
Bmsrv_modify_add_section
static int Bmsrv_modify_add_section(char *url)
Definition: bookmarks.c:1278
modifypage_sections_footer
static const char * modifypage_sections_footer
Definition: bookmarks.c:182
BmRec::url
char * url
Definition: bookmarks.c:59
DPIP_RAW
#define DPIP_RAW
Definition: dpip.h:19
mainpage_sections_item
static const char * mainpage_sections_item
Definition: bookmarks.c:168
dList_new
Dlist * dList_new(int size)
Definition: dlib.c:546
termination_handler
static void termination_handler(int signum)
Definition: bookmarks.c:1684
a_Dpip_dsh_close
void a_Dpip_dsh_close(Dsh *dsh)
Definition: dpip.c:499
dList_remove
void dList_remove(Dlist *lp, const void *data)
Definition: dlib.c:639
make_one_line_str
static char * make_one_line_str(char *str)
Definition: bookmarks.c:409
BmSec::section
int section
Definition: bookmarks.c:64
BmRec::title
char * title
Definition: bookmarks.c:60
modifypage_footer
static const char * modifypage_footer
Definition: bookmarks.c:233
modifypage_add_url
static const char * modifypage_add_url
Definition: bookmarks.c:357
Bms_load
static int Bms_load(void)
Definition: bookmarks.c:722
BmSec::title
char * title
Definition: bookmarks.c:65
mainpage_header
static const char * mainpage_header
Definition: bookmarks.c:93
a_Dpip_dsh_write_str
int a_Dpip_dsh_write_str(Dsh *dsh, int flush, const char *str)
Definition: dpip.c:369
dStrdup
char * dStrdup(const char *s)
Definition: dlib.c:75
modifypage_sections_item
static const char * modifypage_sections_item
Definition: bookmarks.c:172
Header
static char * Header
Definition: bookmarks.c:74
uint_t
unsigned int uint_t
Definition: d_size.h:20
mainpage_sections_header
static const char * mainpage_sections_header
Definition: bookmarks.c:150
modifypage_update_title
static const char * modifypage_update_title
Definition: bookmarks.c:311
Bms_update_title
static void Bms_update_title(int key, char *n_title)
Definition: bookmarks.c:602
MODIFY_PAGE_NUM
static int MODIFY_PAGE_NUM
Definition: bookmarks.c:83
dStrnAsciiCasecmp
int dStrnAsciiCasecmp(const char *s1, const char *s2, size_t n)
Definition: dlib.c:213
INT2VOIDP
#define INT2VOIDP(i)
Definition: dlib.h:44