/[drupal]/contributions/modules/bookmarks2/bookmarks2.module
ViewVC logotype

Contents of /contributions/modules/bookmarks2/bookmarks2.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.14 - (show annotations) (download) (as text)
Sun Jul 27 20:29:00 2008 UTC (15 months, 4 weeks ago) by sanduhrs
Branch: MAIN
CVS Tags: HEAD
Changes since 1.13: +16 -3 lines
File MIME type: text/x-php
Updated password reminder.
1 <?php
2 // $Id: bookmarks2.module,v 1.13 2008/07/27 19:36:41 sanduhrs Exp $
3
4 /**
5 * @file
6 * Lets users keep bookmarks
7 *
8 * @author David Kent Norman
9 * @link http://deekayen.net/
10 * @todo There's some code/functionality duplication to eliminate
11 * Callbacks are underutilized
12 * add option to submit key by SSL
13 * password reminder re-encryption if users enter their old key with a new key
14 */
15
16 /**
17 * Implementation of hook_help().
18 */
19 function bookmarks2_help($path, $arg) {
20 switch ($path) {
21 case 'user/bookmarks2':
22 return t('A bookmark is a link to an address (URL) on the internet.');
23 break;
24 }
25 }
26
27 /**
28 * Implementation of hook_menu().
29 */
30 function bookmarks2_menu() {
31 $items['bookmarks2'] = array(
32 'title' => 'My bookmarks',
33 'page callback' => 'bookmarks2_page',
34 'access arguments' => array('access bookmarks2'),
35 );
36 $items['bookmarks2/overview'] = array(
37 'title' => t('List'),
38 'access arguments' => array('access bookmarks2'),
39 'weight' => -10,
40 'type' => MENU_DEFAULT_LOCAL_TASK,
41 );
42 $items['bookmarks2/add'] = array(
43 'title' => t('Add bookmark'),
44 'page callback' => 'drupal_get_form',
45 'page arguments' => array('bookmarks2_form'),
46 'access arguments' => array('access bookmarks2'),
47 'weight' => 10,
48 'type' => MENU_LOCAL_TASK,
49 );
50 $items['bookmarks2/delete'] = array(
51 'title' => t('Delete bookmark'),
52 'page callback' => 'drupal_get_form',
53 'page arguments' => array('bookmarks2_delete_confirm'),
54 'access arguments' => array('access bookmarks2'),
55 'type' => MENU_CALLBACK,
56 );
57 $items['bookmarks2/folders'] = array(
58 'title' => t('Folders'),
59 'page callback' => 'bookmarks2_folder_overview',
60 'access arguments' => array('access bookmarks2'),
61 'weight' => 15,
62 'type' => MENU_LOCAL_TASK,
63 );
64 $items['bookmarks2/folder/add'] = array(
65 'title' => t('Add folder'),
66 'page callback' => 'drupal_get_form',
67 'page arguments' => array('bookmarks2_folder_form'),
68 'access arguments' => array('access bookmarks2'),
69 'weight' => 20,
70 'type' => MENU_LOCAL_TASK,
71 );
72 $items['bookmarks2/folders/edit'] = array(
73 'title' => t('Edit folder'),
74 'page callback' => 'drupal_get_form',
75 'page arguments' => array('bookmarks2_folder_form'),
76 'access arguments' => array('access bookmarks2'),
77 'weight' => 20,
78 'type' => MENU_LOCAL_TASK,
79 );
80 $items['bookmarks2/folder/delete'] = array(
81 'title' => t('Delete folder'),
82 'page callback' => 'drupal_get_form',
83 'page arguments' => array('bookmarks2_folder_delete_confirm'),
84 'access arguments' => array('access bookmarks2'),
85 'type' => MENU_CALLBACK,
86 );
87 $items['bookmarks2/edit'] = array(
88 'title' => t('Edit bookmark'),
89 'page callback' => 'drupal_get_form',
90 'page arguments' => array('bookmarks2_form'),
91 'access arguments' => array('access bookmarks2'),
92 'type' => MENU_CALLBACK,
93 );
94 $items['bookmarks2/config'] = array(
95 'title' => t('Preferences'),
96 'page callback' => 'drupal_get_form',
97 'page arguments' => array('_bookmarks2_config'),
98 'access arguments' => array('access bookmarks2'),
99 'weight' => 25,
100 'type' => MENU_LOCAL_TASK,
101 );
102
103 $items['bookmarks2/%/rss.xml'] = array(
104 'title' => t('feed'),
105 'page callback' => 'bookmarks2_feed',
106 'page arguments' => array(1),
107 'access arguments' => array('access bookmarks2'),
108 'type' => MENU_CALLBACK,
109 );
110 $items['admin/settings/bookmarks2'] = array(
111 'title' => t('Bookmarks Settings'),
112 'page callback' => 'drupal_get_form',
113 'page arguments' => array('bookmarks2_admin_settings'),
114 'access arguments' => array('administer bookmarks2'),
115 'description' => t('Change bookmarks settings.'),
116 );
117
118 return $items;
119 }
120
121 /**
122 * Implementation of hook_block().
123 */
124 function bookmarks2_block($op = 'list', $delta = 0, $edit = array()) {
125 global $user;
126
127 if ($op == 'list') {
128 $blocks[0] = array (
129 'info' => t('User bookmarks'),
130 );
131 return $blocks;
132 }
133 elseif ($op == 'view') {
134 switch ($delta) {
135 case 0:
136 if ($user->uid != 0 && user_access('access bookmarks2')) {
137 $block = array(
138 'subject' => t('My bookmarks'),
139 'content' => bookmarks2_block_1(),
140 );
141 }
142 break;
143 }
144 return $block;
145 }
146 }
147
148 /**
149 * Returns an user's bookmarks block.
150 */
151 function bookmarks2_block_1() {
152 global $user;
153
154 $result = db_query('SELECT b.url, b.title, b.description, b.options FROM {bookmarks2} b WHERE b.uid = %d ORDER BY b.title', $user->uid);
155 $bookmarks = array();
156 while ($data = db_fetch_object($result)) {
157 $bookmarks[] = '<div class="icon">'. theme('bookmarks2_delete', $data->url) .'</div>'. _bookmarks2_get_link($data->url, $data->title, $data->description, $data->options, true);
158 }
159
160 $links = array(
161 'bookmarks2_quick_link' => array(
162 'title' => t('Quick link'),
163 'href' => "bookmarks2/add/quick",
164 'attributes' => array(
165 'title' => t('Bookmark the current page.'),
166 'class' => 'bookmarks2_link',
167 ),
168 'query' => 'title='. urlencode(drupal_get_title()),
169 ),
170 'bookmarks2_manage' => array(
171 'title' => t('Manage'),
172 'href' => 'bookmarks2',
173 'attributes' => array(
174 'title' => t('Manage your bookmarks.'),
175 'class' => 'bookmarks2_link',
176 ),
177 ),
178 );
179
180 return theme('bookmarks2_block', $bookmarks, $links);
181 }
182
183 /**
184 * Implementation of hook_perm().
185 */
186 function bookmarks2_perm() {
187 return array('administer bookmarks2', 'access bookmarks2');
188 }
189
190 /**
191 * Implementation of hook_theme().
192 */
193 function bookmarks2_theme($existing, $type, $theme, $path) {
194 return array(
195 'bookmarks2_block' => array(
196 'arguments' => array(),
197 ),
198 'bookmarks2_delete' => array(
199 'arguments' => array('url' => NULL),
200 ),
201 );
202 }
203
204 /**
205 * Theme the block
206 */
207 function theme_bookmarks2_block($items = array(), $links = array()) {
208 $output = (count($items) ? theme('item_list', $items) : t('You have no bookmarks.'));
209 $output .= '<div class="links">'. theme('links', $links) .'</div>';
210 return $output;
211 }
212
213 /**
214 * Returns a bookmarks delete icon.
215 */
216 function theme_bookmarks2_delete($url) {
217 $query = 'url='. urlencode($url);
218 return l(theme('image', drupal_get_path('module', 'bookmarks2') .'/trash.gif', t('delete')), "bookmarks2/delete", array('query' => $query, 'html' => TRUE));
219 }
220
221 /**
222 * The controller for managing bookmarks. Callback happens via menu().
223 *
224 * @return string Completely themed HTML page.
225 */
226 function bookmarks2_page() {
227 global $user;
228
229 // Generate overview
230 $output = bookmarks2_overview();
231
232 // Add rss functionality
233 $feed_title = t("!user's bookmarks", array('!user' => $user->name));
234 $feed_url = url('bookmarks2/'. $user->uid .'/rss.xml');
235 drupal_set_html_head('<link rel="alternate" type="application/rss+xml" title="'. $feed_title .'" href="'. $feed_url .'" />');
236 $output .= theme('feed_icon', $feed_url, $feed_title);
237
238 return $output;
239 }
240
241 /**
242 * Output a RSS feed
243 */
244 function bookmarks2_feed() {
245 global $user, $base_url;
246
247 $result = db_query('SELECT b.url, b.title, b.description FROM {bookmarks2} b WHERE b.uid = %d', $user->uid);
248
249 $title = variable_get('site_name', '');
250 $link = $base_url;
251 $description = t("%user's bookmarks", array('%user' => $user->name));
252
253 while ($obj = db_fetch_object($result)) {
254 if (!preg_match('@^\w+://.+@', $obj->url)) {
255 $obj->url = implode('/', array($base_url, $obj->url));
256 }
257 $body .= format_rss_item($obj->title, $obj->url, $obj->description);
258 }
259
260 $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
261 $output .= "<!DOCTYPE rss [<!ENTITY % HTMLlat1 PUBLIC \"-//W3C//ENTITIES Latin1 for XHTML//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent\">]>\n";
262 $output .= "<rss version=\"2.0\" xml:base=\"$base_url\">\n";
263 $output .= format_rss_channel($title, $link, $description, $body);
264 $output .= "</rss>\n";
265
266 drupal_set_header('Content-Type: text/xml; charset=utf-8');
267 print $output;
268 }
269
270 /**
271 * Confirmation screen to make sure user really wants to delete their bookmark
272 */
273 function bookmarks2_delete_confirm(&$form_state = null, $url = NULL, $uid = NULL) {
274 if (!$url) {
275 $url = check_plain($_GET['url']);
276 }
277
278 $form['url'] = array(
279 '#type' => 'hidden',
280 '#value' => $url,
281 );
282 return confirm_form($form, t('Are you sure you want to delete this bookmark?'), 'bookmarks2', NULL, t('Delete'));
283 }
284
285 /**
286 * Actually deletes a bookmark after a confirmation on a previous screen
287 *
288 * @param string $form_id
289 * @param array $form_values
290 * @return string
291 */
292 function bookmarks2_delete_confirm_submit($form, &$form_state) {
293 global $user;
294
295 db_query("DELETE FROM {bookmarks2} WHERE uid = %d AND url = '%s'", $user->uid, $form_state['values']['url']);
296 drupal_set_message(t('Deleted bookmark.'));
297
298 drupal_goto('bookmarks2');
299 }
300
301 /**
302 * Menu callback; confirm deletion of folder.
303 *
304 * @todo name the folder in the question
305 */
306 function bookmarks2_folder_delete_confirm(&$form_state, $fid = NULL) {
307 if (!$fid) {
308 $fid = (int) check_plain($_GET['fid']);
309 }
310
311 $form['fid'] = array(
312 '#type' => 'hidden',
313 '#value' => $fid,
314 );
315 return confirm_form($form, t('Are you sure you want to delete this folder?'), 'bookmarks2/folders', NULL, t('Delete'));
316 }
317
318
319 /**
320 * Delete a folder, all its children, and the associated bookmarks
321 *
322 * @param int $fid
323 * @return string
324 */
325 function bookmarks2_folder_delete_confirm_submit($form, &$form_state, $fid = 0, $child = false) {
326 //dprint_r($form_state);
327 global $user;
328
329 if ($child) {
330 $result = db_query('SELECT f.fid FROM {bookmarks2_folders} f WHERE f.uid = %d AND f.fid = %d', $user->uid, $fid);
331 while ($data = db_fetch_object($result)) {
332 db_query('DELETE FROM {bookmarks2} WHERE uid = %d AND fid = %d', $user->uid, $data->fid);
333 db_query('DELETE FROM {bookmarks2_folders} WHERE uid = %d AND fid = %d', $user->uid, $data->fid);
334 bookmarks2_folder_delete_confirm_submit(NULL, NULL, $data->fid, true);
335 }
336 }
337 else {
338 if (!is_numeric($form_state['values']['fid'])) {
339 drupal_set_message(t('Folder ID is not the correct format!', 'error'));
340 }
341 else {
342 db_query('DELETE FROM {bookmarks2} WHERE uid = %d AND fid = %d', $user->uid, $form_state['values']['fid']);
343 db_query('DELETE FROM {bookmarks2_folders} WHERE uid = %d AND fid = %d', $user->uid, $form_state['values']['fid']);
344 drupal_set_message(t('Deleted bookmark folder.'));
345 }
346
347 drupal_goto('bookmarks2/folders');
348 }
349 }
350
351 /**
352 * Get a folder tree
353 */
354 function _bookmarks2_folder_select_options() {
355 $folders = _bookmarks2_folder_child(true);
356 if ($edit != NULL) {
357 $current_name = $folders[$edit['fid']];
358 $current_childs = array($edit['fid'] => $current_name);
359 _bookmarks2_folder_child_loop($edit['fid'], $current_childs, (strpos($current_name, '>') / 2));
360 $folders = array_diff_assoc($folders, $current_childs);
361 }
362 return $folders;
363 }
364
365 /**
366 * Bookmark creation and update form
367 */
368 function bookmarks2_form(&$form_state) {
369 if (arg(2) == 'quick') {
370 $edit = bookmarks2_load_quicklink();
371 }
372 if (arg(1) == 'edit' && is_string($_GET['url'])) {
373 $edit = bookmarks2_load(check_plain($_GET['url']));
374 }
375
376 $form['details'] = array(
377 '#type' => 'fieldset',
378 '#title' => t('Bookmark details')
379 );
380 $form['details']['title'] = array(
381 '#type' => 'textfield',
382 '#title' => t('Title'),
383 '#default_value' => $edit['title'],
384 '#size' => 60,
385 '#maxlength' => 128,
386 '#description' => null,
387 '#attributes' => null,
388 '#required' => true
389 );
390 $form['details']['url'] = array(
391 '#type' => 'textfield',
392 '#title' => t('URL'),
393 '#default_value' => $edit['url'],
394 '#size' => 60,
395 '#maxlength' => 128,
396 '#description' => t('Enter the address of the page you want to bookmark. This can be an internal or external reference.'),
397 '#attributes' => null,
398 '#required' => true
399 );
400 $form['details']['_blank'] = array(
401 '#type' => 'checkbox',
402 '#title' => t('Open bookmark clicks in a new window'),
403 '#return_value' => 1,
404 '#default_value' => $edit['options'] & 1
405 );
406 $form['details']['description'] = array(
407 '#type' => 'textarea',
408 '#title' => t('Description'),
409 '#default_value' => $edit['description'],
410 '#rows' => 4,
411 '#cols' => 68,
412 '#description' => t('Optionally enter a description for this bookmark for reference later.'),
413 '#required' => false
414 );
415 if (variable_get('bookmarks2_login_reminder_enabled', false) && _bookmarks2_crypt_ok()) {
416 $form['details']['reminder'] = array(
417 '#type' => 'fieldset',
418 '#title' => t('Login reminder'),
419 '#collapsible' => true,
420 '#collapsed' => true
421 );
422 $form['details']['reminder']['uname'] = array(
423 '#type' => 'textfield',
424 '#title' => t('Bookmark URL username'),
425 '#default_value' => $edit['uname'],
426 '#size' => 60,
427 '#maxlength' => 80,
428 '#description' => t('Username is stored in plaintext'),
429 '#required' => false
430 );
431 if (_bookmarks2_key_isset()) {
432 $form['details']['reminder']['pword'] = array(
433 '#type' => 'password',
434 '#title' => t('Bookmark URL password'),
435 '#default_value' => '',
436 '#size' => 60,
437 '#maxlength' => 255,
438 '#description' => t('Password will be secured with 256-bit encryption when stored.'),
439 '#required' => false
440 );
441 $form['details']['reminder']['key'] = array(
442 '#type' => 'password',
443 '#title' => t('Password locking key'),
444 '#default_value' => '',
445 '#size' => 60,
446 '#maxlength' => 255,
447 '#description' => t('This key is used to secure your password reminder with 256-bit encryption. It was set in your bookmark preferences.'),
448 '#required' => false
449 );
450 }
451 }
452 $form['details']['fid'] = array(
453 '#type' => 'select',
454 '#title' => t('Parent folder'),
455 '#options' => _bookmarks2_folder_select_options(),
456 '#default_value' => $edit['fid'],
457 '#multiple' => false,
458 '#required' => true
459 );
460 $form['old_url'] = array(
461 '#type' => 'hidden',
462 '#value' => urlencode($edit['url'])
463 );
464 $form['submit'] = array(
465 '#type' => 'submit',
466 '#value' => t('Save')
467 );
468 return $form;
469 }
470
471 /**
472 * Form validation
473 */
474 function bookmarks2_form_validate($form, &$form_state) {
475 if ((isset($form_state['values']['pword']) && $form_state['values']['pword'] == '') && (!isset($form_state['values']['key']) || !$form_state['values']['key'])) {
476 form_set_error('pword', t('You must supply your bookmark reminder key to encrypt the password for your login reminder.'));
477 }
478 elseif ($form_state['values']['key'] && !_bookmarks2_check_key($form_state['values']['key'])) {
479 form_set_error('key', t('The reminder key you supplied does not match the one on record.'));
480 }
481 }
482
483 /**
484 * Form submit handler
485 */
486 function bookmarks2_form_submit($form, &$form_state) {
487 global $user;
488
489 $encrypted_pword = '';
490 $options = 0;
491 $options |= ($form_state['values']['_blank']) ? $form_state['values']['_blank'] : 0;
492
493 if ($form_state['values']['pword'] && $form_state['values']['key']) {
494 $encrypted_pword = _bookmarks2_encrypt_pword($form_state['values']['key'], $form_state['values']['pword']);
495 }
496
497 $form_state['values']['old_url'] = urldecode($form_state['values']['old_url']);
498 if ($form_state['values']['old_url'] && db_result(db_query("SELECT COUNT(b.uid) FROM {bookmarks2} b WHERE b.uid = %d AND b.url = '%s'", $user->uid, $form_state['values']['old_url']))) {
499 if (!$form_state['values']['pword'] && !$form_state['values']['key']) {
500 $encrypted_pword = db_result(db_query("SELECT pword FROM {bookmarks2} b WHERE b.uid = %d AND b.url = '%s'", $user->uid, $form_state['values']['old_url']));
501 }
502 db_query("UPDATE {bookmarks2} SET fid = %d, title = '%s', url = '%s', description = '%s', uname = '%s', pword = '%s', options = %d WHERE uid = %d AND url = '%s'", $form_state['values']['fid'], $form_state['values']['title'], $form_state['values']['url'], $form_state['values']['description'], $form_state['values']['uname'], $encrypted_pword, $options, $user->uid, $form_state['values']['old_url']);
503 drupal_set_message(t('The bookmark has been updated.'));
504 }
505 else {
506 db_query("INSERT INTO {bookmarks2} (uid, fid, url, title, description, uname, pword, options) VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', %d)", $user->uid, $form_state['values']['fid'], $form_state['values']['url'], $form_state['values']['title'], $form_state['values']['description'], $form_state['values']['uname'], $encrypted_pword, $options);
507 drupal_set_message(t('The link has been added to your bookmarks.'));
508 }
509 }
510
511 /**
512 * Bookmark folder creation and update form
513 */
514 function bookmarks2_folder_form($form_state) {
515 if (arg(2) == 'edit' && is_numeric($_GET['fid'])) {
516 $edit = _bookmarks2_folder_load(check_plain($_GET['fid']));
517 }
518
519 $form['details'] = array(
520 '#type' => 'fieldset',
521 '#title' => t('Folder details')
522 );
523 $form['details']['fname'] = array(
524 '#type' => 'textfield',
525 '#title' => t('Folder name'),
526 '#default_value' => $edit['fname'],
527 '#size' => 60,
528 '#maxlength' => 128,
529 '#required' => true
530 );
531 $form['details']['f_parent_id'] = array(
532 '#type' => 'select',
533 '#title' => t('Parent folder'),
534 '#options' => _bookmarks2_folder_select_options(),
535 '#default_value' => $edit['f_parent_id'],
536 '#multiple' => false,
537 '#required' => true
538 );
539 $form['fid'] = array(
540 '#type' => 'hidden',
541 '#value' => $edit['fid']
542 );
543 $form['submit'] = array(
544 '#type' => 'submit',
545 '#value' => 'Save folder'
546 );
547
548 return $form;
549 }
550
551 /**
552 * Update or save a bookmark folder
553 */
554 function bookmarks2_folder_form_submit($form, &$form_state) {
555 global $user;
556
557 if (db_result(db_query("SELECT COUNT(fid) FROM {bookmarks2_folders} WHERE fid = %d AND uid = %d", $form_state['values']['fid'], $user->uid))) {
558 db_query("UPDATE {bookmarks2_folders} SET fname = '%s', f_parent_id = %d WHERE uid = %d AND fid = %d", $form_state['values']['fname'], $form_state['values']['f_parent_id'], $user->uid, $form_state['values']['fid']);
559 drupal_set_message(t('The folder has been updated.'));
560 }
561 else {
562 db_query("INSERT INTO {bookmarks2_folders} (uid, f_parent_id, fname) VALUES (%d, %d, '%s')", $user->uid, $form_state['values']['f_parent_id'], $form_state['values']['fname']);
563 drupal_set_message(t('The folder has been added to your bookmarks.'));
564 }
565 }
566
567 /**
568 * Let individuals set preferences for bookmarks in the bookmark preferences tab
569 */
570 function _bookmarks2_config() {
571 $form['link_display'] = array(
572 '#type' => 'radios',
573 '#title' => t('Link display'),
574 '#default_value' => _bookmarks2_user_pref('link_display', 0),
575 '#options' => array(t('Title and link separate'), t('Title as link')),
576 '#description' => t('Either show the bookmark name as a link, or the title with the URL as a separate link')
577 );
578 if (variable_get('bookmarks2_login_reminder_enabled', false) && _bookmarks2_crypt_ok()) {
579 $form['details']['reminder'] = array(
580 '#type' => 'fieldset',
581 '#title' => t('Login reminder'),
582 '#collapsible' => true,
583 '#collapsed' => true
584 );
585 $key_set = _bookmarks2_key_isset();
586 $form['details']['reminder']['key'] = array(
587 '#type' => 'password',
588 '#title' => t('Password lock/unlock key'),
589 '#default_value' => '',
590 '#size' => 60,
591 '#maxlength' => 255,
592 '#description' => t('The key is currently <em style="color: %color">%set</em>. ', array('%set' => $key_set ? t('set') : t('not set'), '%color' => $key_set ? 'green' : 'red')) .
593 t('This key will be scrambled with 256-bit, one-way encryption and will be needed to lock and unlock your password reminders. If you submit a new key when one is already set, all your password reminders <strong>will be deleted</strong> because the new key will not be a valid verification for decrypting your stored passwords.'),
594 '#required' => false
595 );
596 }
597 $form['submit'] = array(
598 '#type' => 'submit',
599 '#value' => 'Save preferences'
600 );
601
602 return $form;
603 }
604
605 /**
606 * Grabs a user's preferences for bookmarks from the database
607 */
608 function _bookmarks2_user_pref($var, $default) {
609 static $options;
610
611 if (!isset($options)) {
612 $options = db_result(db_query("SELECT options FROM {bookmarks2_prefs} WHERE uid = %d", $GLOBALS['user']->uid));
613 }
614 $definitions = array(
615 'link_display' => 1 // display link title as link
616 );
617 return $options ? $options & $definitions[$var] : $default;
618 }
619
620 /**
621 * Write prefs to db
622 */
623 function _bookmarks2_config_submit($form, &$form_state) {
624 global $user;
625
626 $options = 0;
627 $options |= $form_state['values']['link_display'];
628 $key = false;
629 $existing_key = _bookmarks2_fetch_key();
630
631 if ($existing_key && empty($form_state['values']['key'])) {
632 $key = $existing_key;
633 }
634 elseif (!empty($form_state['values']['key'])) {
635 $key = _bookmarks2_hash_key($form_state['values']['key']);
636 db_query("UPDATE {bookmarks2} SET pword = '' WHERE uid = %d", $user->uid);
637 }
638
639 if ($key) {
640 db_query("REPLACE INTO {bookmarks2_prefs} (uid, options, pword_key) VALUES (%d, %d, '%s')", $user->uid, $options, $key);
641 }
642 else {
643 db_query("REPLACE INTO {bookmarks2_prefs} (uid, options) VALUES (%d, %d)", $user->uid, $options);
644 }
645 drupal_set_message(t('Bookmark preferences have been updated.'));
646 }
647
648 /**
649 * Grab the bookmarks for a user from the database
650 *
651 * @param string $url
652 * @return array
653 */
654 function bookmarks2_load($url) {
655 global $user;
656 return db_fetch_array(db_query("SELECT * FROM {bookmarks2} WHERE uid = %d AND url = '%s'", $user->uid, $url));
657 }
658
659 /**
660 * Grab the name of a bookmark's folder for a user from the database
661 *
662 * @param int $fid Folder id
663 * @return array
664 */
665 function _bookmarks2_folder_load($fid) {
666 global $user;
667 return db_fetch_array(db_query("SELECT * FROM {bookmarks2_folders} WHERE uid = %d AND fid = %d", $user->uid, $fid));
668 }
669
670 /**
671 *
672 *
673 * @return array
674 */
675 function bookmarks2_load_quicklink() {
676
677 $edit['url'] = bookmarks2_get_canonical_path($url);
678 $explicit_uri = drupal_get_normal_path($edit['url']);
679
680 $uri_ary = explode('/', $explicit_uri);
681 $type = $uri_ary[0];
682 foreach ($uri_ary as $value) {
683 if (is_numeric($value)) {
684 $id = $value;
685 break;
686 }
687 }
688
689 /* Only display quicklink title for internal URLs */
690 if (is_numeric($id) && !strstr($edit['url'], 'http://')) {
691 switch ($type) {
692 case 'node':
693 $edit['title'] = db_result(db_query('SELECT title FROM {node} n WHERE nid = %d', $id));
694 break;
695 case 'comment':
696 $edit['title'] = db_result(db_query('SELECT subject FROM {comments} WHERE cid = %d', $id));
697 break;
698 case 'user':
699 $edit['title'] = db_result(db_query('SELECT name FROM {users} WHERE uid = %d', $id));
700 break;
701 default:
702 /* Leave the title blank. The user will be prompted to enter a title. */
703 }
704 }
705
706 if (!$edit['title']) {
707 $edit['title'] = urldecode($_GET['title']);
708 }
709
710 return $edit;
711 }
712
713 /**
714 * Main bookmark list
715 *
716 * @return string
717 */
718 function bookmarks2_overview() {
719 global $user;
720 $key = isset($_POST['overview_key']) ? $_POST['overview_key'] : '';
721
722 $crypt_ok = _bookmarks2_crypt_ok() && variable_get('bookmarks2_login_reminder_enabled', 0);
723 $good_key = _bookmarks2_check_key($key);
724 if ($key && !$good_key) {
725 drupal_set_message(t('Password reminder key incorrect! Password reminders will not be shown.'), 'error');
726 }
727 $link_display = _bookmarks2_user_pref('link_display', 0);
728
729
730
731 $header[] = array('data' => t('title'), 'field' => 'title', 'sort' => 'asc');
732 if (!$link_display) {
733 $header[] = array('data' => t('link'), 'field' => 'url');
734 }
735 if ($crypt_ok) {
736 /*
737 $form['key_holder'] = array(
738 '#type' => 'fieldset',
739 '#title' => t('Reveal password reminders'),
740 '#collapsible' => true, '#collapsed' => true
741 );
742 $form['key_holder']['key'] = array(
743 '#type' => 'password',
744 '#size' => 20,
745 '#description' => t('Enter your password reminder key to decrypt and reveal your saved passwords')
746 );
747 $form['key_holder']['submit'] = array(
748 '#type' => 'submit',
749 '#value' => t('Display password reminders')
750 );
751 $output .= drupal_get_form('bookmarks2_key', $form);
752 //die(var_dump($_POST)); // outputs an empty array after a form submission
753 */
754 // this is the output of the above $form since drupal_get_form is making $key disappear in a HTTP redirect or something
755 if (_bookmarks2_key_isset()) {
756 $output .= '<form action="" method="post" id="bookmarks2_key">
757 <div><fieldset class=" collapsible"><legend>'. t('Reveal password reminders') .'</legend><div class="form-item">
758 <input type="password" maxlength="" name="overview_key" id="edit-key" size="20" class="form-text" />
759 <div class="description">'. t('Enter your password reminder key to decrypt and reveal your saved passwords') .'</div>
760 </div><input type="submit" name="op" value="'. t('Display password reminders') .'" class="form-submit" />
761 </fieldset></div></form>';
762 }
763
764 $header[] = array('data' => t('username'), 'field' => 'uname');
765 $header[] = array('data' => t('password'), 'field' => 'pword');
766 if ($good_key) {
767 drupal_set_header('Pragma: no-cache');
768 drupal_set_header('Cache-Control: no-cache');
769 drupal_set_html_head('<meta http-equiv="Pragma" content="no-cache" /><meta http-equiv="Expires" content="-1" /><meta http-equiv="Cache-Control" content="no-cache" />');
770 }
771 }
772 $header[] = array('data' => t('operations'), 'colspan' => 2);
773
774 $result = db_query('SELECT b.url, b.title, b.description, b.uname, b.pword, b.options FROM {bookmarks2} b
775 WHERE b.uid = %d AND b.fid = 0'. tablesort_sql($header), $user->uid);
776
777 $rows = array();
778 while ($data = db_fetch_object($result)) {
779 if ($crypt_ok) {
780 if (empty($data->pword)) {
781 $decrypted_pword = '';
782 }
783 elseif ($good_key) {
784 $decrypted_pword = _bookmarks2_decrypt_pword($key, $data->pword);
785 }
786 else {
787 $decrypted_pword = '<em>'. t('hidden') .'</em>';
788 }
789
790 if ($link_display) {
791 $rows[] = array(
792 _bookmarks2_get_link($data->url, $data->title, $data->description, $data->options, $link_display),
793 $data->uname,
794 $decrypted_pword,
795 l(t('edit'), "bookmarks2/edit", array('query' => 'url='. urlencode($data->url))),
796 l(t('delete'), "bookmarks2/delete", array('query' => 'url='. urlencode($data->url)))
797 );
798 }
799 else {
800 $rows[] = array(
801 $data->title,
802 _bookmarks2_get_link($data->url, $data->title, $data->description, $data->options, $link_display),
803 $data->uname,
804 $decrypted_pword,
805 l(t('edit'), "bookmarks2/edit", array('query' => 'url='. urlencode($data->url))),
806 l(t('delete'), "bookmarks2/delete", array('query' => 'url='. urlencode($data->url)))
807 );
808 }
809
810 }
811 else {
812
813 if ($link_display) {
814 $rows[] = array(
815 _bookmarks2_get_link($data->url, $data->title, $data->description, $data->options, $link_display),
816 l(t('edit'), "bookmarks2/edit", array('query' => 'url='. urlencode($data->url))),
817 l(t('delete'), "bookmarks2/delete", array('query' => 'url='. urlencode($data->url))),
818 );
819 }
820 else {
821 $rows[] = array(
822 $data->title,
823 _bookmarks2_get_link($data->url, $data->title, $data->description, $data->options, $link_display),
824 l(t('edit'), "bookmarks2/edit", array('query' => 'url='. urlencode($data->url))),
825 l(t('delete'), "bookmarks2/delete", array('query' => 'url='. urlencode($data->url))),
826 );
827 }
828
829 }
830 }
831
832 $output .= drupal_get_form('_bookmarks2_overview_folders', $link_display, 0, $key, $crypt_ok, $good_key);
833 $output .= (count($rows) == 0) ? t('You have no bookmarks.') : theme('table', $header, $rows);
834 return $output;
835 }
836
837 /**
838 * List the folders a user has created for their bookmarks
839 *
840 * @todo do something about ugly code duplication from bookmarks2_overview()
841 * @see bookmarks2_overview()
842 * @param bool $link_display
843 * @param int $fid
844 * @return string
845 */
846 function _bookmarks2_overview_folders($form_state, $link_display, $fid = 0, $key = '', $crypt_ok = false, $good_key = false) {
847 global $user;
848
849 $form = array();
850 // having all these queries probably isn't the most efficient way of doing this
851 $f_result = db_query('SELECT f.fid, f.fname FROM {bookmarks2_folders} f WHERE f.f_parent_id = %d AND f.uid = %d ORDER BY f.fname', $fid, $user->uid);
852 while ($folder_data = db_fetch_object($f_result)) {
853 if (!isset($form[$folder_data->fid])) {
854 $form[$folder_data->fid] = array(
855 '#type' => 'fieldset',
856 '#title' => check_plain($folder_data->fname),
857 '#collapsible' => true,
858 '#collapsed' => true
859 );
860 }
861 if ($child = drupal_get_form('_bookmarks2_overview_folders', $link_display, $folder_data->fid, $key, $crypt_ok, $good_key)) {
862 $form[$folder_data->fid]['child'] = array(
863 '#value' => $child
864 );
865 }
866
867 $header = array();
868 $header[] = array('data' => t('title'), 'field' => 'title', 'sort' => 'asc');
869 if (!$link_display) {
870 $header[] = array('data' => t('link'), 'field' => 'url');
871 }
872 if ($crypt_ok) {
873 $header[] = array('data' => t('username'), 'field' => 'uname');
874 $header[] = array('data' => t('password'), 'field' => 'pword');
875 }
876 $header[] = array('data' => t('operations'), 'colspan' => 2);
877 if ($bm_result = db_query('SELECT b.url, b.title, b.description, b.uname, b.pword, b.options FROM {bookmarks2} b WHERE b.uid = %d AND b.fid = %d '. tablesort_sql($header), $user->uid, $folder_data->fid)) {
878
879 $rows = array();
880
881 while ($data = db_fetch_object($bm_result)) {
882 if ($crypt_ok) {
883 if (empty($data->pword)) {
884 $decrypted_pword = '';
885 }
886 elseif ($good_key) {
887 $decrypted_pword = _bookmarks2_decrypt_pword($key, $data->pword);
888 }
889 else {
890 $decrypted_pword = '<em>'. t('hidden') .'</em>';
891 }
892 if ($link_display) {
893 $rows[] = array(
894 _bookmarks2_get_link($data->url, $data->title, $data->description, $data->options, $link_display),
895 $data->uname,
896 $decrypted_pword,
897 l(t('edit'), "bookmarks2/edit", array('query' => 'url='. urlencode($data->url))),
898 l(t('delete'), "bookmarks2/delete", array('query' => 'url='. urlencode($data->url)))
899 );
900 }
901 else {
902 $rows[] = array(
903 $data->title,
904 _bookmarks2_get_link($data->url, $data->title, $data->description, $data->options, $link_display),
905 $data->uname,
906 $decrypted_pword,
907 l(t('edit'), "bookmarks2/edit", array('query' => 'url='. urlencode($data->url))),
908 l(t('delete'), "bookmarks2/delete", array('query' => 'url='. urlencode($data->url)))
909 );
910 }
911 }
912 else {
913 if ($link_display) {
914 $rows[] = array(
915 _bookmarks2_get_link($data->url, $data->title, $data->description, $data->options, $link_display),
916 l(t('edit'), "bookmarks2/edit", array('query' => 'url='. urlencode($data->url))),
917 l(t('delete'), "bookmarks2/delete", array('query' => 'url='. urlencode($data->url)))
918 );
919 }
920 else {
921 $rows[] = array(
922 $data->title,
923 _bookmarks2_get_link($data->url, $data->title, $data->description, $data->options, $link_display),
924 l(t('edit'), "bookmarks2/edit", array('query' => 'url='. urlencode($data->url))),
925 l(t('delete'), "bookmarks2/delete", array('query' => 'url='. urlencode($data->url)))
926 );
927 }
928 }
929 }
930 $form[$folder_data->fid][$data->url] = array(
931 '#value' => theme('table', $header, $rows)
932 );
933 }
934 }
935 return $form;
936 }
937
938 /**
939 * List folders bookmarks can be stored in
940 *
941 * @return string
942 */
943 function bookmarks2_folder_overview() {
944 global $user;
945
946 $header = array(
947 array('data' => t('Name')),
948 array('data' => t('Operations'), 'colspan' => 2),
949 );
950
951 $folders = _bookmarks2_folder_child();
952
953 while (list($key, $value) = each($folders)) {
954 $fname = (strlen($value) > 50) ? substr($value, 0, 47) .'...' : $value;
955 $rows[] = array(
956 $value,
957 l(t('edit'), 'bookmarks2/folders/edit', array('query' => 'fid='. $key)),
958 l(t('delete'), 'bookmarks2/folder/delete', array('query' => 'fid='. $key)));
959 }
960
961 $output .= !count($rows) ? t('You have no folders.') : theme('table', $header, $rows);
962 return $output;
963 }
964
965 /**
966 * Pull hierarchy of folders from the database
967 *
968 * @param bool $inc_top
969 * @return array
970 */
971 function _bookmarks2_folder_child($inc_top = false) {
972 global $user;
973
974 $folder_tree = $inc_top == true ? array(0 => '['. t('Top level') .']') : array();
975
976 $result = db_query('SELECT f.fid, f.fname FROM {bookmarks2_folders} f WHERE f.f_parent_id = 0 AND f.uid = %d ORDER BY f.fname', $user->uid);
977 while ($data = db_fetch_object($result)) {
978 if ($_GET['fid'] != $data->fid) {
979 $folder_tree[$data->fid] = $data->fname;
980 _bookmarks2_folder_child_loop($data->fid, $folder_tree, 0);
981 }
982 }
983 return $folder_tree;
984 }
985
986 /**
987 * Recursive loop to grab layers of folders under the top level
988 *
989 * @param int $fid
990 * @param array $folder_array
991 * @param int $i
992 */
993 function _bookmarks2_folder_child_loop($fid, &$folder_array, $i) {
994 global $user;
995
996 $i++; // should this be static?
997 $result = db_query('SELECT f.fid, f.fname FROM {bookmarks2_folders} f WHERE f.f_parent_id = %d AND f.uid = %d ORDER BY f.fname', $fid, $user->uid);
998 while ($data = db_fetch_object($result)) {
999 $folder_array[$data->fid] = str_repeat('-', 2*$i) .' '. $data->fname;
1000 if ($data->fid != $fid) {
1001 _bookmarks2_folder_child_loop($data->fid, $folder_array, $i);
1002 }
1003 }
1004 }
1005
1006 /**
1007 * Updates or saves bookmarks
1008 *
1009 * @param array $edit
1010 */
1011 function bookmarks2_save($edit) {
1012 global $user;
1013
1014 $encrypted_pword = '';
1015 $options = 0;
1016 $options |= ($edit['_blank']) ? $edit['_blank'] : 0;
1017
1018 if ($edit['pword'] && $edit['key']) {
1019 $encrypted_pword = _bookmarks2_encrypt_pword($edit['key'], $edit['pword']);
1020 }
1021
1022 $edit['old_url'] = urldecode($edit['old_url']);
1023 if ($edit['old_url'] && db_result(db_query("SELECT COUNT(b.uid) FROM {bookmarks2} b WHERE b.uid = %d AND b.url = '%s'", $user->uid, $edit['old_url']))) {
1024 if (!$edit['pword'] && !$edit['key']) {
1025 $encrypted_pword = db_result(db_query("SELECT pword FROM {bookmarks2} b WHERE b.uid = %d AND b.url = '%s'", $user->uid, $edit['old_url']));
1026 }
1027 db_query("UPDATE {bookmarks2} SET fid = %d, title = '%s', url = '%s', description = '%s', uname = '%s', pword = '%s', options = %d WHERE uid = %d AND url = '%s'", $edit['fid'], $edit['title'], $edit['url'], $edit['description'], $edit['uname'], $encrypted_pword, $options, $user->uid, $edit['old_url']);
1028 drupal_set_message(t('The bookmark has been updated.'));
1029 }
1030 else {
1031 db_query("INSERT INTO {bookmarks2} (uid, fid, url, title, description, uname, pword, options) VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', %d)", $user->uid, $edit['fid'], $edit['url'], $edit['title'], $edit['description'], $edit['uname'], $encrypted_pword, $options);
1032 drupal_set_message(t('The link has been added to your bookmarks.'));
1033 }
1034 }
1035
1036 /**
1037 * Administration settings to turn on password reminder or not
1038 *
1039 * @return array
1040 */
1041 function bookmarks2_admin_settings() {
1042 $form['bookmarks2_link_crop_size'] = array(
1043 '#type' => 'textfield',
1044 '#title' => t('Link crop length'),
1045 '#description' => t('The display of links will be cropped to this length in characters.'),
1046 '#size' => 5,
1047 '#maxlength' => 5,
1048 '#default_value' => variable_get('bookmarks2_link_crop_size', 50)
1049 );
1050 if (_bookmarks2_crypt_ok()) {
1051 $form['bookmarks2_login_reminder_enabled'] = array(
1052 '#type' => 'radios',
1053 '#title' => t('Enable login reminder support'),
1054 '#options' => array(t('No'), t('Yes')),
1055 '#default_value' => variable_get('bookmarks2_login_reminder_enabled', '0'),
1056 '#description' => t('Gives users the option to store a username and password reminder for each bookmark. The password gets stored with strong encryption when the user correctly enters their password reminder key. Administrators are not able to read or recover the password or encryption key.')
1057 );
1058 }
1059 else {
1060 $form['bookmarks2_login_reminder'] = array('#type' => 'markup', '#value' => t('The mcrypt extension of PHP must be installed on this server for login reminders to work.'));
1061 $form['bookmarks2_login_reminder_enabled'] = array('#type' => 'hidden', '#value' => '0');
1062 }
1063
1064 return system_settings_form($form);
1065 }
1066
1067 /**
1068 * Return a relative URI that Drupal can recognize internally.
1069 *
1070 * @return string
1071 */
1072 function bookmarks2_get_canonical_path($url) {
1073 global $base_url;
1074
1075 $c_path = ltrim(str_replace($base_url, '', trim(referer_uri(), '/')), '/');
1076 $c_path = str_replace('index.php', '', $c_path);