plugins/links/functions.inc
author Dirk Haun <dirk@haun-online.de>
Sat, 07 Nov 2009 18:31:22 +0100
branchHEAD
changeset 7453 825540f1937d
parent 7342 187ee0efcee2
child 7596 a411f5d356bb
permissions -rw-r--r--
Links plugin: When URL rewriting is enabled, return rewritten URLs for search results
     1 <?php
     2 
     3 // Reminder: always indent with 4 spaces (no tabs).
     4 // +---------------------------------------------------------------------------+
     5 // | Links Plugin 2.1                                                          |
     6 // +---------------------------------------------------------------------------+
     7 // | functions.inc                                                             |
     8 // |                                                                           |
     9 // | This file does two things: 1) it implements the necessary Geeklog Plugin  |
    10 // | API method and 2) implements all the common code needed by the Links      |
    11 // | Plugins' PHP files.                                                       |
    12 // +---------------------------------------------------------------------------+
    13 // | Copyright (C) 2000-2009 by the following authors:                         |
    14 // |                                                                           |
    15 // | Authors: Tony Bibbs         - tony AT tonybibbs DOT com                   |
    16 // |          Mark Limburg       - mlimburg AT users.sourceforge DOT net       |
    17 // |          Jason Whittenburg  - jwhitten AT securitygeeks DOT com           |
    18 // |          Dirk Haun          - dirk AT haun-online DOT de                  |
    19 // |          Trinity Bays       - trinity93 AT gmail DOT com                  |
    20 // |          Oliver Spiesshofer - oliver AT spiesshofer DOT com               |
    21 // |          Euan McKay         - info AT heatherengineering DOT com          |
    22 // +---------------------------------------------------------------------------+
    23 // |                                                                           |
    24 // | This program is licensed under the terms of the GNU General Public License|
    25 // | as published by the Free Software Foundation; either version 2            |
    26 // | of the License, or (at your option) any later version.                    |
    27 // |                                                                           |
    28 // | This program is distributed in the hope that it will be useful,           |
    29 // | but WITHOUT ANY WARRANTY; without even the implied warranty of            |
    30 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                      |
    31 // | See the GNU General Public License for more details.                      |
    32 // |                                                                           |
    33 // | You should have received a copy of the GNU General Public License         |
    34 // | along with this program; if not, write to the Free Software Foundation,   |
    35 // | Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.           |
    36 // |                                                                           |
    37 // +---------------------------------------------------------------------------+
    38 
    39 /**
    40 * Implementation of the Plugin API for the Links plugin
    41 *
    42 * @package Links
    43 */
    44 
    45 if (strpos(strtolower($_SERVER['PHP_SELF']), 'functions.inc') !== false) {
    46     die('This file can not be used on its own.');
    47 }
    48 
    49 $plugin_path = $_CONF['path'] . 'plugins/links/';
    50 
    51 /**
    52 * Language file include
    53 */
    54 $langfile = $plugin_path . 'language/' . $_CONF['language'] . '.php';
    55 if (file_exists($langfile)) {
    56     require_once $langfile;
    57 } else {
    58     require_once $plugin_path . 'language/english.php';
    59 }
    60 
    61 /**
    62 * Check and see if we need to load the plugin configuration
    63 */
    64 if (!isset($_LI_CONF['linksloginrequired'])) {
    65     require_once $_CONF['path_system'] . 'classes/config.class.php';
    66 
    67     $li_config = config::get_instance();
    68     $_LI_CONF = $li_config->get_config('links');
    69 }
    70 
    71 
    72 // +---------------------------------------------------------------------------+
    73 // | Geeklog Plugin API Implementation                                         |
    74 // +---------------------------------------------------------------------------+
    75 
    76 /**
    77 * Returns the items for this plugin that should appear on the main menu
    78 *
    79 * NOTE: this MUST return the url/value pairs in the following format
    80 * $<arrayname>[<label>] = <url>
    81 *
    82 * @return   mixed   menu entry, or boolean false if disabled / hidden
    83 *
    84 */
    85 function plugin_getmenuitems_links()
    86 {
    87     global $_CONF, $_LI_CONF, $LANG_LINKS;
    88 
    89     if (($_LI_CONF['hidelinksmenu'] == 1) || (COM_isAnonUser() &&
    90                 ($_CONF['loginrequired'] || $_LI_CONF['linksloginrequired']))) {
    91         return false;
    92     }
    93 
    94     $menuitems[$LANG_LINKS[114]] = $_CONF['site_url'] . '/links/index.php';
    95 
    96     return $menuitems;
    97 }
    98 
    99 /**
   100 * Return headlines for New Links section in the What's New block, if enabled
   101 *
   102 * @return   mixed       array(headline, byline), or boolean false if disabled
   103 *
   104 */
   105 function plugin_whatsnewsupported_links()
   106 {
   107     global $_LI_CONF, $LANG_LINKS, $LANG_WHATSNEW;
   108 
   109     if ($_LI_CONF['hidenewlinks'] == 0) {
   110         $retval = array($LANG_LINKS[84],
   111                         COM_formatTimeString($LANG_WHATSNEW['new_last'],
   112                                              $_LI_CONF['newlinksinterval'])
   113                        );
   114     } else {
   115         $retval = false;
   116     }
   117 
   118     return $retval;
   119 }
   120 
   121 /**
   122 * Return new links for the What's New block
   123 *
   124 * @return   string  HTML list of new links
   125 *
   126 */
   127 function plugin_getwhatsnew_links()
   128 {
   129     global $_CONF, $_TABLES, $_USER, $_LI_CONF, $LANG_LINKS;
   130 
   131     $retval = '';
   132 
   133     // Get newest links
   134     $sql = "SELECT lid,title FROM {$_TABLES['links']} WHERE (date >= (DATE_SUB(NOW(), INTERVAL {$_LI_CONF['newlinksinterval']} SECOND)))" . COM_getPermSQL('AND') . LINKS_getCategorySQL('AND') . ' ORDER BY date DESC LIMIT 15';
   135     $result = DB_query($sql);
   136     $nrows = DB_numRows($result);
   137 
   138     if ($nrows > 0) {
   139         $newlinks = array();
   140         for ($x = 0; $x < $nrows; $x++) {
   141             $A = DB_fetchArray($result);
   142             $A['title'] = stripslashes($A['title']);
   143 
   144             // redirect link via portal.php so we can count the clicks
   145             $lcount = COM_buildUrl($_CONF['site_url']
   146                     . '/links/portal.php?what=link&amp;item=' . $A['lid']);
   147 
   148             $title = COM_truncate($A['title'], $_CONF['title_trim_length'],
   149                                   '...');
   150             $link_title = array();
   151             if ($title != $A['title']) {
   152                 $link_title = array('title' => $A['title']);
   153             }
   154 
   155             $newlinks[] = COM_createLink($title, $lcount, $link_title) . LB;
   156         }
   157 
   158         $retval .= COM_makeList($newlinks, 'list-new-plugins');
   159     } else {
   160         $retval .= $LANG_LINKS[88] . '<br' . XHTML . '>' . LB;
   161     }
   162 
   163     return $retval;
   164 }
   165 
   166 /**
   167 * Implements the [link:] autotag.
   168 *
   169 * @param    string  $op         operation to perform
   170 * @param    string  $content    item (e.g. story text), including the autotag
   171 * @param    array   $autotag    parameters used in the autotag
   172 * @param    mixed               tag names (for $op='tagname') or formatted content
   173 *
   174 */
   175 function plugin_autotags_links($op, $content = '', $autotag = '')
   176 {
   177     global $_CONF, $_TABLES, $LANG_DIRECTION;
   178 
   179     if ($op == 'tagname' ) {
   180         return 'link';
   181     } else if ($op == 'parse') {
   182         $lid = COM_applyFilter($autotag['parm1']);
   183         if (! empty($lid)) {
   184             $url = COM_buildUrl($_CONF['site_url']
   185                             . '/links/portal.php?what=link&amp;item=' . $lid);
   186             if (empty($autotag['parm2'])) {
   187                 $result = DB_query("SELECT url, title FROM {$_TABLES['links']} WHERE lid = '$lid'");
   188                 list($siteurl, $linktext) = DB_fetchArray($result);
   189                 $linktext = stripslashes($linktext);
   190             } else {
   191                 $linktext = $autotag['parm2'];
   192                 $siteurl = DB_getItem($_TABLES['links'], 'url', "lid = '$lid'");
   193             }
   194             $class = 'ext-link';
   195             if ((!empty($LANG_DIRECTION)) && ($LANG_DIRECTION == 'rtl')) {
   196                 $class .= '-rtl';
   197             }
   198             $attr = array(
   199                         'title' => $siteurl,
   200                         'class' => $class
   201                          );
   202             $link = COM_createLink($linktext, $url, $attr);
   203             $content = str_replace($autotag['tagstr'], $link, $content);
   204         }
   205 
   206         return $content;
   207     }
   208 }
   209 
   210 /**
   211 * Called by the plugin Editor to display the current plugin code version
   212 * This may be different than the version installed and registered currently.
   213 * If newer then you may want to run the update
   214 *
   215 * @return   string  version number
   216 *
   217 */
   218 function plugin_chkVersion_links ()
   219 {
   220     global $_CONF;
   221 
   222     require_once $_CONF['path'] . 'plugins/links/autoinstall.php';
   223 
   224     $inst_parms = plugin_autoinstall_links('links');
   225 
   226     return $inst_parms['info']['pi_version'];
   227 }
   228 
   229 /**
   230 * Helper function: count number of links and total number of clicks
   231 *
   232 * @return   array(number of links, number of clicks);
   233 *
   234 */
   235 function LINKS_countLinksAndClicks()
   236 {
   237     global $_TABLES;
   238 
   239     $result = DB_query("SELECT COUNT(*) AS count,SUM(hits) AS clicks FROM {$_TABLES['links']}" . COM_getPermSQL() . LINKS_getCategorySQL('AND'));
   240     $A = DB_fetchArray($result);
   241     $total_links = $A['count'];
   242     $total_clicks = $A['clicks'];
   243     if (empty($total_clicks)) {
   244         $total_clicks = 0;
   245     }
   246 
   247     return array($total_links, $total_clicks);
   248 }
   249 
   250 /**
   251 * Shows the statistics for the links plugin on stats.php.
   252 * If $showsitestats is 1 then we are to only print the overall stats in the
   253 * 'site statistics box' otherwise we show the detailed stats
   254 *
   255 * @param    int     $showsitestate  Flag to let us know which stats to get
   256 * @param    string                  HTML for the stats section
   257 *
   258 */
   259 function plugin_showstats_links ($showsitestats)
   260 {
   261     global $_CONF, $_TABLES, $LANG_LINKS_STATS;
   262 
   263     require_once $_CONF['path_system'] . 'lib-admin.php';
   264 
   265     $retval = '';
   266 
   267     $result = DB_query("SELECT lid,url,title,hits FROM {$_TABLES['links']} WHERE (hits > 0)" . COM_getPermSQL('AND') . LINKS_getCategorySQL('AND') . " ORDER BY hits DESC LIMIT 10");
   268     $nrows  = DB_numRows ($result);
   269     if ($nrows > 0) {
   270         $header_arr = array(
   271             array('text'         => $LANG_LINKS_STATS['stats_page_title'],
   272                   'field'        => 'sid',
   273                   'header_class' => 'stats-header-title'
   274             ),
   275             array('text'         => $LANG_LINKS_STATS['stats_hits'],
   276                   'field'        => 'hits',
   277                   'header_class' => 'stats-header-count',
   278                   'field_class'  => 'stats-list-count'
   279             )
   280         );
   281         $data_arr = array();
   282         $text_arr = array('has_menu' => false,
   283                           'title'    => $LANG_LINKS_STATS['stats_headline'],
   284         );
   285         for ($i = 0; $i < $nrows; $i++) {
   286             $A = DB_fetchArray ($result);
   287             $title = stripslashes (str_replace ('$', '&#36;', $A['title']));
   288             $url = COM_buildUrl ($_CONF['site_url']
   289                         . '/links/portal.php?what=link&amp;item=' . $A['lid']);
   290             $sid = COM_createLink($title, $url, array('title' => $A['url']));
   291             $hits = COM_numberFormat ($A['hits']);
   292             $data_arr[] = array('title' => $title,
   293                                 'sid' => $sid,
   294                                 'hits' => $hits
   295                           );
   296         }
   297         $retval .= ADMIN_simpleList ('', $header_arr, $text_arr, $data_arr);
   298     } else {
   299         $retval .= COM_startBlock ($LANG_LINKS_STATS['stats_headline']);
   300         $retval .= $LANG_LINKS_STATS['stats_no_hits'];
   301         $retval .= COM_endBlock ();
   302     }
   303 
   304     return $retval;
   305 }
   306 
   307 /**
   308 * New stats plugin API function for proper integration with the site stats
   309 *
   310 * @return   array(item text, item count);
   311 *
   312 */
   313 function plugin_statssummary_links ()
   314 {
   315     global $LANG_LINKS_STATS;
   316 
   317     list($total_links, $total_clicks) = LINKS_countLinksAndClicks ();
   318 
   319     $item_count = COM_NumberFormat ($total_links)
   320                 . ' (' . COM_NumberFormat ($total_clicks) . ')';
   321 
   322 
   323     return array ($LANG_LINKS_STATS['links'], $item_count);
   324 }
   325 
   326 /**
   327 * Geeklog is asking us to provide any items that show up in the type
   328 * drop-down on search.php.  Let's users search for links.
   329 *
   330 * @return   array   (plugin name/entry title) pair for the dropdown
   331 *
   332 */
   333 function plugin_searchtypes_links()
   334 {
   335     global $LANG_LINKS;
   336 
   337     $tmp['links'] = $LANG_LINKS[14];
   338 
   339     return $tmp;
   340 }
   341 
   342 
   343 /**
   344 * This searches for links matching the user query and returns an array for the
   345 * header and table rows back to search.php where it will be formated and printed
   346 *
   347 * @param    string  $query      Keywords user is looking for
   348 * @param    date    $datestart  Start date to get results for
   349 * @param    date    $dateend    End date to get results for
   350 * @param    string  $topic      The topic they were searching in
   351 * @param    string  $type       Type of items they are searching, or 'all' (deprecated)
   352 * @param    int     $author     Get all results by this author
   353 * @param    string  $keyType    search key type: 'all', 'phrase', 'any'
   354 * @param    int     $page       page number of current search (deprecated)
   355 * @param    int     $perpage    number of results per page (deprecated)
   356 * @return   object              search result object
   357 *
   358 */
   359 function plugin_dopluginsearch_links($query, $datestart, $dateend, $topic, $type, $author, $keyType, $page, $perpage)
   360 {
   361     global $_TABLES, $LANG_LINKS;
   362 
   363     // Make sure the query is SQL safe
   364     $query = trim(addslashes($query));
   365 
   366     $sql = "SELECT lid AS id, title, description, UNIX_TIMESTAMP(date) AS date, owner_id AS uid, hits, ";
   367     $sql .= "CONCAT('/links/portal.php?what=link&amp;item=', lid) AS url ";
   368     $sql .= "FROM {$_TABLES['links']} WHERE date <> 1 ";
   369     $sql .= COM_getPermSQL('AND') . ' ';
   370 
   371     if (!empty ($author)) {
   372         $sql .= "AND (owner_id = '$author') ";
   373     }
   374 
   375     $search = new SearchCriteria('links', $LANG_LINKS[14]);
   376 
   377     $columns = array('title' => 'title', 'description');
   378     $sql .= $search->getDateRangeSQL('AND', 'date', $datestart, $dateend);
   379     list($sql,$ftsql) = $search->buildSearchSQL($keyType, $query, $columns, $sql);
   380 
   381     $search->setSQL($sql);
   382     $search->setFTSQL($ftsql);
   383     $search->setRank(3);
   384     $search->setAppendQuery(false);
   385     $search->setURLRewrite(true);
   386 
   387     return $search;
   388 }
   389 
   390 
   391 /**
   392 * This will put an option for links in the command and control block on
   393 * moderation.php
   394 *
   395 * @return   mixed   array(title, url, icon), or boolean false when not allowed
   396 *
   397 */
   398 function plugin_cclabel_links()
   399 {
   400     global $_CONF, $LANG_LINKS;
   401 
   402     if (SEC_hasRights ('links.edit')) {
   403         return array ($LANG_LINKS[14],
   404                       $_CONF['site_admin_url'] . '/plugins/links/index.php',
   405                       plugin_geticon_links ());
   406     }
   407 
   408     return false;
   409 }
   410 
   411 /**
   412 * returns the administrative option for this plugin
   413 *
   414 * @return   mixed   array(title, url, num. links), or void when not allowed
   415 *
   416 */
   417 function plugin_getadminoption_links()
   418 {
   419     global $_CONF, $_TABLES, $LANG_LINKS;
   420 
   421     if (SEC_hasRights ('links.edit,links.delete', 'OR')) {
   422         $total_links = DB_getItem ($_TABLES['links'], 'COUNT(*)',
   423                                    COM_getPermSql (''));
   424 
   425         return array ($LANG_LINKS[14],
   426                       $_CONF['site_admin_url'] . '/plugins/links/index.php',
   427                       $total_links);
   428     }
   429 }
   430 
   431 /**
   432 * A user is about to be deleted. Update ownership of any links owned
   433 * by that user or delete them.
   434 *
   435 * @param    int     $uid    User id of deleted user
   436 * @return   void
   437 *
   438 */
   439 function plugin_user_delete_links ($uid)
   440 {
   441     global $_TABLES, $_LI_CONF;
   442 
   443     if (DB_count ($_TABLES['links'], 'owner_id', $uid) == 0) {
   444         return;
   445     }
   446 
   447     if ($_LI_CONF['delete_links'] == 1) {
   448         // delete the links
   449         DB_delete($_TABLES['links'], 'owner_id', $uid);
   450     } else {
   451         // assign ownership to a user from the Root group
   452         $rootgroup = DB_getItem ($_TABLES['groups'], 'grp_id',
   453                                  "grp_name = 'Root'");
   454         $result = DB_query ("SELECT DISTINCT ug_uid FROM {$_TABLES['group_assignments']} WHERE ug_main_grp_id = $rootgroup ORDER BY ug_uid LIMIT 1");
   455         $A = DB_fetchArray ($result);
   456         $rootuser = $A['ug_uid'];
   457         DB_query ("UPDATE {$_TABLES['links']} SET owner_id = $rootuser WHERE owner_id = $uid");
   458     }
   459 }
   460 
   461 /**
   462 * Do we support feeds?
   463 *
   464 * @return   array   id/name pairs of all supported feeds
   465 *
   466 */
   467 function plugin_getfeednames_links()
   468 {
   469     global $_TABLES;
   470 
   471     $feeds = array ();
   472 
   473     $result = DB_query ("SELECT cid,category FROM {$_TABLES['linkcategories']} GROUP BY category ORDER BY category ASC");
   474     $num = DB_numRows ($result);
   475 
   476     if ($num > 0) {
   477         $feeds[] = array ('id' => 'all', 'name' => 'all categories');
   478 
   479         for ($i = 0; $i < $num; $i++) {
   480             $A = DB_fetchArray ($result);
   481             $feeds[] = array ('id' => $A['cid'], 'name' => $A['category']);
   482         }
   483     }
   484 
   485     return $feeds;
   486 }
   487 
   488 /**
   489 * Provide feed data
   490 *
   491 * @param    int     $feed       feed ID
   492 * @param    ref     $link
   493 * @param    ref     $update
   494 * @return   array               feed entries
   495 *
   496 */
   497 function plugin_getfeedcontent_links ($feed, &$link, &$update)
   498 {
   499     global $_CONF, $_TABLES;
   500 
   501     $result = DB_query( "SELECT topic,limits,content_length FROM {$_TABLES['syndication']} WHERE fid = '$feed'" );
   502     $S = DB_fetchArray( $result );
   503 
   504     $result = DB_query( "SELECT lid,owner_id,title,description,UNIX_TIMESTAMP(date) AS modified FROM " . $_TABLES['links'] . links_buildSql ($S['topic'], $S['limits']) );
   505 
   506     $content = array();
   507     $lids = array();
   508     $nrows = DB_numRows( $result );
   509 
   510     for( $i = 0; $i < $nrows; $i++ )
   511     {
   512         $row = DB_fetchArray( $result );
   513         $lids[] = $row['lid'];
   514 
   515         $linktitle = stripslashes( $row['title'] );
   516         $linkdesc = stripslashes( $row['description'] );
   517 
   518         $linklink = COM_buildUrl( $_CONF['site_url']
   519                   . '/links/portal.php?what=link&amp;item=' . $row['lid'] );
   520 
   521         $content[] = array( 'title'   => $linktitle,
   522                             'summary' => $linkdesc,
   523                             'link'    => $linklink,
   524                             'uid'     => $row['owner_id'],
   525                             'author'  => COM_getDisplayName( $row['owner_id'] ),
   526                             'date'    => $row['modified'],
   527                             'format'  => 'plaintext'
   528                           );
   529     }
   530 
   531     $link = $_CONF['site_url'] . '/links/index.php';
   532     $update = implode( ',', $lids );
   533 
   534     return $content;
   535 }
   536 
   537 /**
   538 * Helper function: Build part of an SQL request
   539 *
   540 * @param    string  $cid        category id
   541 * @param    string  $limits     limit (number of entries or number of hours)
   542 * @return   string              part of an SQL request
   543 *
   544 */
   545 function links_buildSql($cid, $limits)
   546 {
   547     $where = '';
   548     if ($cid != 'all') {
   549         $where = "cid='" . addslashes($cid) . "'";
   550     }
   551 
   552     $limitsql = '';
   553     if (!empty ($limits)) {
   554         if (substr ($limits, -1) == 'h') { // last xx hours
   555             $limitsql = '';
   556             $hours = substr ($limits, 0, -1);
   557             if (!empty ($where)) {
   558                 $where .= ' AND ';
   559             }
   560             $where .= "date >= DATE_SUB(NOW(),INTERVAL $hours HOUR)";
   561         } else {
   562             $limitsql = ' LIMIT ' . $limits;
   563         }
   564     }
   565     else
   566     {
   567         $limitsql = ' LIMIT 10';
   568     }
   569 
   570     if (!empty ($where)) {
   571         $where = ' WHERE ' . $where;
   572     }
   573 
   574     $sql = $where . ' ORDER BY date DESC' . $limitsql;
   575 
   576     return $sql;
   577 }
   578 
   579 /**
   580 * Checking if links feeds are up to date
   581 *
   582 * @param    int     $feed           id of feed to be checked
   583 * @param    string  $topic          topic (actually: cid)
   584 * @param    string  $update_data    data describing current feed contents
   585 * @param    string  $limit          number of entries or number of hours
   586 * @param    string  $updated_type   (optional) type of feed to be updated
   587 * @param    string  $updated_topic  (optional) feed's "topic" to be updated
   588 * @param    string  $updated_id     (optional) id of entry that has changed
   589 * @return   boolean                 true: feed data is up to date; false: isn't
   590 *
   591 */
   592 function plugin_feedupdatecheck_links ($feed, $topic, $update_data, $limit, $updated_type = '', $updated_topic = '', $updated_id = '')
   593 {
   594     global $_TABLES;
   595 
   596     $is_current = true;
   597 
   598     if ($updated_type != 'links') {
   599         // we're not interested
   600         $updated_type = '';
   601         $updated_topic = '';
   602         $updated_id = '';
   603     }
   604 
   605     $sql = "SELECT lid FROM {$_TABLES['links']}" . links_buildSql ($topic, $limit);
   606     $result = DB_query ($sql);
   607     $num = DB_numRows ($result);
   608 
   609     $lids = array ();
   610     for ($i = 0; $i < $num; $i++) {
   611         $A = DB_fetchArray ($result);
   612 
   613         if ($A['lid'] == $updated_id) {
   614             // this feed has to be updated - no further checks needed
   615             return false;
   616         }
   617 
   618         $lids[] = $A['lid'];
   619     }
   620     $current = implode (',', $lids);
   621 
   622     return ($current != $update_data) ? false : true;
   623 }
   624 
   625 /**
   626 * Update the Links plugin
   627 *
   628 * @return   int     Number of message to display (true = generic success msg)
   629 *
   630 */
   631 function plugin_upgrade_links()
   632 {
   633     global $_CONF, $_TABLES, $_LI_CONF;
   634 
   635     $installed_version = DB_getItem($_TABLES['plugins'], 'pi_version',
   636                                     "pi_name = 'links'");
   637     $code_version = plugin_chkVersion_links();
   638     if ($installed_version == $code_version) {
   639         // nothing to do
   640         return true;
   641     }
   642 
   643     require_once $_CONF['path'] . 'plugins/links/autoinstall.php';
   644 
   645     if (! plugin_compatible_with_this_version_links('links')) {
   646         return 3002;
   647     }
   648 
   649     $inst_parms = plugin_autoinstall_links('links');
   650     $pi_gl_version = $inst_parms['info']['pi_gl_version'];
   651 
   652     if (! isset($_LI_CONF['new_window'])) {
   653         $c = config::get_instance();
   654         $c->add('new_window',false,'select',0,0,1,55,TRUE,'links');
   655     }
   656 
   657     if (! isset($_LI_CONF['category_permissions'])) {
   658         $c = config::get_instance();
   659         $c->add('fs_cpermissions', NULL, 'fieldset', 0, 3, NULL, 0, true, 'links');
   660         $c->add('category_permissions', array (3, 2, 2, 2),
   661                 '@select', 0, 3, 12, 150, true, 'links');
   662     }
   663 
   664     DB_query("UPDATE {$_TABLES['plugins']} SET pi_version = '$code_version', pi_gl_version = '$pi_gl_version' WHERE pi_name = 'links'");
   665 
   666     return true;
   667 }
   668 
   669 /**
   670 * Called during site migration - handle changed URLs or paths
   671 *
   672 * @param    array   $old_conf   contents of the $_CONF array on the old site
   673 * @param    boolean             true on success, otherwise false
   674 *
   675 */
   676 function plugin_migrate_links($old_conf)
   677 {
   678     global $_CONF;
   679 
   680     $tables = array(
   681         'linkcategories'    => 'cid, description',
   682         'links'             => 'lid, description, url',
   683         'linksubmission'    => 'lid, description, url'
   684     );
   685 
   686     if ($old_conf['site_url'] != $_CONF['site_url']) {
   687         INST_updateSiteUrl($old_conf['site_url'], $_CONF['site_url'], $tables);
   688     }
   689 
   690     return true;
   691 }
   692 
   693 /**
   694 * Geeklog informs us that we're about to be enabled or disabled
   695 *
   696 * @param    boolean     $enable     true = we're being enabled, false = disabled
   697 * @return   void
   698 *
   699 */
   700 function plugin_enablestatechange_links ($enable)
   701 {
   702     global $_TABLES;
   703 
   704     $is_enabled = $enable ? 1 : 0;
   705 
   706     // toggle links feeds
   707     DB_query ("UPDATE {$_TABLES['syndication']} SET is_enabled = $is_enabled WHERE type = 'links'");
   708 }
   709 
   710 /**
   711 * Counts the items that are submitted
   712 *
   713 * @return   int     number of items in submission queue
   714 *
   715 */
   716 function plugin_submissioncount_links()
   717 {
   718     global $_TABLES;
   719 
   720     $retval = 0;
   721 
   722     if (plugin_ismoderator_links ()) {
   723         $retval = DB_count ($_TABLES['linksubmission']);
   724     }
   725 
   726     return $retval;
   727 }
   728 
   729 /**
   730 * Checks that the current user has the rights to moderate the
   731 * plugin, returns true if this is the case, false otherwise
   732 *
   733 * @return        boolean       Returns true if moderator
   734 *
   735 */
   736 function plugin_ismoderator_links()
   737 {
   738     return SEC_hasRights ('links.moderate');
   739 }
   740 
   741 
   742 /**
   743 * Returns SQL & Language texts to moderation.php
   744 *
   745 * @return   mixed   plugin object or void if not allowed
   746 *
   747 */
   748 function plugin_itemlist_links()
   749 {
   750     global $_TABLES, $LANG_LINKS_SUBMIT;
   751 
   752     if (plugin_ismoderator_links()) {
   753         $plugin = new Plugin();
   754         $plugin->submissionlabel = $LANG_LINKS_SUBMIT[11];
   755         $plugin->submissionhelpfile = 'cclinksubmission.html';
   756         $plugin->getsubmissionssql = "SELECT lid AS id,title,cid AS category,url FROM {$_TABLES['linksubmission']} ORDER BY title ASC";
   757         $plugin->addSubmissionHeading($LANG_LINKS_SUBMIT[8]);
   758         $plugin->addSubmissionHeading($LANG_LINKS_SUBMIT[10]);
   759         $plugin->addSubmissionHeading($LANG_LINKS_SUBMIT[9]);
   760 
   761         return $plugin;
   762     }
   763 }
   764 
   765 /**
   766 * returns list of moderation values
   767 *
   768 * The array returned contains (in order): the row 'id' label, main plugin
   769 * table, moderation fields (comma seperated), and plugin submission table
   770 *
   771 * @return       array        Returns array of useful moderation values
   772 *
   773 */
   774 function plugin_moderationvalues_links()
   775 {
   776     global $_TABLES;
   777 
   778     return array ('lid',
   779                   $_TABLES['links'],
   780                   'lid,cid,url,description,title,date,owner_id',
   781                   $_TABLES['linksubmission']);
   782 }
   783 
   784 
   785 /**
   786 * Performs plugin exclusive work for items approved by moderation
   787 *
   788 * While moderation.php handles the actual move from linkssubmission
   789 * to links tables, within the function we handle all other approval
   790 * relate tasks
   791 *
   792 * @param    string  $id     Identifying string
   793 * @return   string          Any wanted HTML output
   794 *
   795 */
   796 function plugin_moderationapprove_links($id)
   797 {
   798     global $_TABLES, $_USER, $_GROUPS, $_LI_CONF;
   799 
   800     // The linksubmission only keeps track of the submitter's uid, but not
   801     // of grous and permissions. So set those to sensible defaults.
   802 
   803     if (isset($_GROUPS['Links Admin'])) {
   804         $group_id = $_GROUPS['Links Admin'];
   805     } else {
   806         $group_id = SEC_getFeatureGroup('links.moderate');
   807     }
   808 
   809     $A = array();
   810     SEC_setDefaultPermissions($A, $_LI_CONF['default_permissions']);
   811 
   812     DB_query("UPDATE {$_TABLES['links']} SET group_id = '$group_id', perm_owner = '{$A['perm_owner']}', perm_group = '{$A['perm_group']}', perm_members = '{$A['perm_members']}', perm_anon = '{$A['perm_anon']}' WHERE lid = '$id'");
   813 
   814     return '';
   815 }
   816 
   817 /**
   818 * Performs plugin exclusive work for items deleted by moderation
   819 *
   820 * While moderation.php handles the actual removal from <plugin>submission
   821 * table, within this function we handle all other deletion
   822 * related tasks
   823 *
   824 * @param    string  $id     Identifying string
   825 * @return   string          Any wanted HTML output
   826 *
   827 */
   828 function plugin_moderationdelete_links($id)
   829 {
   830     global $_TABLES;
   831 
   832     // these tables should not contain any rows with ml_id = $id
   833     // this is done 'just in case'
   834     DB_delete ($_TABLES['linksubmission'], 'lid', $id);
   835 
   836     return '';
   837 }
   838 
   839 /**
   840 * Check submission form values and save if OK. Else show form again
   841 *
   842 * @param    array   $A  The link record
   843 * @return   string      Any wanted HTML output
   844 *
   845 */
   846 function plugin_savesubmission_links($A)
   847 {
   848     global $LANG12;
   849 
   850     $retval = '';
   851 
   852     if (!empty ($A['title']) && !empty ($A['description']) &&
   853                 !empty ($A['url'])) {
   854         $retval = plugin_save_submit_links ($A);
   855     } else {
   856         $retval .= COM_siteHeader()
   857             . COM_startBlock ($LANG12[22], '',
   858                            COM_getBlockTemplate ('_msg_block', 'header'))
   859             . $LANG12[23]
   860             . COM_endBlock (COM_getBlockTemplate ('_msg_block', 'footer'))
   861             . submissionform('links')
   862             . COM_siteFooter ();
   863     }
   864 
   865     return $retval;
   866 }
   867 
   868 /**
   869 * Shows link submission form
   870 *
   871 * @return   string  HTML for the link submission form
   872 *
   873 */
   874 function plugin_submit_links()
   875 {
   876     global $_CONF, $LANG_LINKS_SUBMIT, $LANG12;
   877 
   878     $retval = COM_startBlock ($LANG_LINKS_SUBMIT[1], 'submitlink.html');
   879 
   880     $linkform = new Template($_CONF['path'] . 'plugins/links/templates');
   881     $linkform->set_file('linkform', 'submitlink.thtml');
   882     $linkform->set_var('site_url', $_CONF['site_url']);
   883     $linkform->set_var('layout_url', $_CONF['layout_url']);
   884     $linkform->set_var('lang_title', $LANG12[10]);
   885     $linkform->set_var('lang_link', $LANG_LINKS_SUBMIT[2]);
   886     $linkform->set_var('lang_category', $LANG_LINKS_SUBMIT[3]);
   887     $category = '';
   888     if (isset($_REQUEST['cid'])) {
   889         $category = $_REQUEST['cid'];
   890     }
   891     $linkform->set_var('link_category_options', links_select_box(2, $category));
   892     $linkform->set_var('lang_description', $LANG12[15]);
   893     $linkform->set_var('lang_htmlnotallowed', $LANG12[35]);
   894     $linkform->set_var('lang_submit', $LANG12[8]);
   895     $linkform->set_var('max_url_length', 255);
   896     $linkform->set_var('xhtml', XHTML);
   897     $linkform->parse('theform', 'linkform');
   898     $retval .= $linkform->finish($linkform->get_var('theform'));
   899     $retval .= COM_endBlock();
   900 
   901     return $retval;
   902 }
   903 
   904 /**
   905 * Saves a link submission
   906 *
   907 * @param    array   $A  Data for that submission
   908 * @return   string      HTML redirect
   909 *
   910 */
   911 function plugin_save_submit_links($A)
   912 {
   913     global $_CONF, $_TABLES, $_USER, $_LI_CONF, $LANG12;
   914 
   915     $retval = '';
   916 
   917     // pseudo-formatted link description for the spam check
   918     $spamcheck = '<p>'. COM_createLink($A['title'], $A['url']) .' ('
   919                . $A['categorydd'] . ')<br' . XHTML . '>' . $A['description']
   920                . '</p>';
   921     $result = PLG_checkforSpam($spamcheck, $_CONF['spamx']);
   922     if ($result > 0) {
   923         COM_updateSpeedlimit('submit');
   924         COM_displayMessageAndAbort($result, 'spamx', 403, 'Forbidden');
   925     }
   926 
   927     $A['cid'] = strip_tags(COM_stripslashes($A['categorydd']));
   928 
   929     $validcat = false;
   930     if (!empty($A['cid'])) {
   931         $cid = addslashes($A['cid']);
   932         $cat = DB_getItem($_TABLES['linkcategories'], 'category',
   933                           "cid = '$cid'");
   934         if (!empty($cat)) {
   935             $validcat = true;
   936         }
   937     }
   938     if (!$validcat) {
   939         $retval .= COM_startBlock($LANG12[22], '',
   940                        COM_getBlockTemplate('_msg_block', 'header'))
   941                 . $LANG12[23]
   942                 . COM_endBlock(COM_getBlockTemplate('_msg_block', 'footer'))
   943                 . submissionform('links')
   944                 . COM_siteFooter();
   945 
   946         return $retval;
   947     }
   948 
   949     $A['cid'] = addslashes($A['cid']);
   950     $A['description'] = addslashes(htmlspecialchars(COM_checkWords($A['description'])));
   951     $A['title'] = addslashes(strip_tags(COM_checkWords($A['title'])));
   952     $A['url'] = addslashes(COM_sanitizeUrl($A['url']));
   953     $A['lid'] = addslashes(COM_makeSid());
   954 
   955     COM_updateSpeedlimit('submit');
   956     if (COM_isAnonUser()) {
   957         $owner_id = 1; // anonymous user
   958     } else {
   959         $owner_id = $_USER['uid'];
   960     }
   961 
   962     if (($_LI_CONF['linksubmission'] == 1) && !SEC_hasRights('links.submit')) {
   963         $result = DB_save($_TABLES['linksubmission'],
   964                     'lid,cid,url,description,title,date,owner_id',
   965                     "{$A['lid']},'{$A['cid']}','{$A['url']}','{$A['description']}','{$A['title']}',NOW(),$owner_id");
   966 
   967         if ($_LI_CONF['notification'] == 1) {
   968             LINKS_sendNotification($_TABLES['linksubmission'], $A);
   969         }
   970 
   971         $retval = COM_refresh($_CONF['site_url']
   972                               . '/index.php?msg=1&amp;plugin=links');
   973 
   974     } else { // add link directly
   975 
   976         if (SEC_hasRights('links.submit')) {
   977             $A['group_id'] = SEC_getFeatureGroup('links.submit');
   978         } else {
   979             $A['group_id'] = DB_getItem($_TABLES['groups'], 'grp_id',
   980                                         "grp_name = 'All Users'");
   981         }
   982         SEC_setDefaultPermissions($A, $_LI_CONF['default_permissions']);
   983 
   984         $result = DB_save($_TABLES['links'],
   985                     'lid,cid,url,description,title,date,owner_id,group_id,perm_owner,perm_group,perm_members,perm_anon',
   986                     "{$A['lid']},'{$A['cid']}','{$A['url']}','{$A['description']}','{$A['title']}',NOW(),$owner_id,{$A['group_id']},{$A['perm_owner']},{$A['perm_group']},{$A['perm_members']},{$A['perm_anon']}");
   987 
   988         PLG_itemSaved($A['lid'], 'links');
   989 
   990         if ($_LI_CONF['notification'] == 1) {
   991             LINKS_sendNotification($_TABLES['links'], $A);
   992         }
   993         COM_rdfUpToDateCheck('links', $A['cid'], $A['lid']);
   994 
   995         $retval = COM_refresh($_CONF['site_url']
   996                               . '/index.php?msg=4&amp;plugin=links');
   997     }
   998 
   999     return $retval;
  1000 }
  1001 
  1002 /**
  1003 * Send an email notification for a new submission.
  1004 *
  1005 * @param    string  $table  Table where the new submission can be found
  1006 * @param    array   $A      submission data
  1007 *
  1008 */
  1009 function LINKS_sendNotification ($table, $A)
  1010 {
  1011     global $_CONF, $_TABLES, $LANG_LINKS, $LANG_LINKS_SUBMIT, $LANG08;
  1012 
  1013     $title = stripslashes ($A['title']);
  1014     $description = stripslashes ($A['description']);
  1015 
  1016     $mailbody = "$LANG_LINKS_SUBMIT[8]: $title\n"
  1017               . "$LANG_LINKS_SUBMIT[9]: <{$A['url']}>\n"
  1018               . "$LANG_LINKS_SUBMIT[3]: {$A['category']}\n\n"
  1019               . $description . "\n\n";
  1020     if ($table == $_TABLES['linksubmission']) {
  1021         $mailbody .= "$LANG_LINKS[10] <{$_CONF['site_admin_url']}/moderation.php>\n\n";
  1022     } else {
  1023         $mailbody .= "$LANG_LINKS[114] <{$_CONF['site_url']}/links/index.php?category=" . urlencode ($A['category']) . ">\n\n";
  1024     }
  1025     $mailsubject = $_CONF['site_name'] . ' ' . $LANG_LINKS_SUBMIT[11];
  1026 
  1027     $mailbody .= "\n------------------------------\n";
  1028     $mailbody .= "\n$LANG08[34]\n";
  1029     $mailbody .= "\n------------------------------\n";
  1030 
  1031     COM_mail ($_CONF['site_mail'], $mailsubject, $mailbody);
  1032 }
  1033 
  1034 /**
  1035 * Returns the URL of the plugin's icon
  1036 *
  1037 * @return   string      URL of the icon
  1038 *
  1039 */
  1040 function plugin_geticon_links ()
  1041 {
  1042     global $_CONF;
  1043 
  1044     return $_CONF['site_url'] . '/links/images/links.png';
  1045 }
  1046 
  1047 function plugin_getListField_links($fieldname, $fieldvalue, $A, $icon_arr)
  1048 {
  1049     global $_CONF, $LANG_ACCESS, $LANG_LINKS_ADMIN;
  1050 
  1051     $retval = '';
  1052 
  1053     $access = SEC_hasAccess($A['owner_id'],$A['group_id'],$A['perm_owner'],$A['perm_group'],$A['perm_members'],$A['perm_anon']);
  1054     if ($access > 0) {
  1055         switch($fieldname) {
  1056             case 'edit':
  1057                 if ($access == 3) {
  1058                     $retval = COM_createLink(
  1059                         $icon_arr['edit'],
  1060                         "{$_CONF['site_admin_url']}/plugins/links/index.php?mode=edit&amp;lid={$A['lid']}"
  1061                     );
  1062                 }
  1063                 break;
  1064             case 'access':
  1065                 if ($access == 3) {
  1066                    $retval = $LANG_ACCESS['edit'];
  1067                 } else {
  1068                    $retval = $LANG_ACCESS['readonly'];
  1069                 }
  1070                 break;
  1071             case 'title':
  1072                 $retval = COM_createLink(stripslashes($A['title']), $A['url']);
  1073                 break;
  1074             case 'dovalidate';
  1075                 $retval = links_validateUrl($A['url']);
  1076                 break;
  1077             case 'beforevalidate';
  1078                 $retval = $LANG_LINKS_ADMIN[57];
  1079                 break;
  1080             case 'category':
  1081                 if (isset($A['indent'])) {
  1082                     $indent = ($A['indent'] - 1) * 20;
  1083                 } else {
  1084                     $indent = 0;
  1085                 }
  1086                 $cat = COM_createLink($A['category'],
  1087                         "{$_CONF['site_url']}/links/index.php?category="
  1088                         . urlencode($A['cid']));
  1089                 $retval = "<span style=\"padding-left:{$indent}px;\">$cat</span>";
  1090                 break;
  1091                 break;
  1092             default:
  1093                 $retval = $fieldvalue;
  1094                 break;
  1095         }
  1096     }
  1097 
  1098     return $retval;
  1099 }
  1100 
  1101 function plugin_getListField_categories($fieldname, $fieldvalue, $A, $icon_arr)
  1102 {
  1103     global $_CONF, $_TABLES, $LANG_ACCESS, $LANG_LINKS_ADMIN;
  1104 
  1105     $retval = '';
  1106 
  1107     $access = SEC_hasAccess($A['owner_id'],$A['group_id'],$A['perm_owner'],$A['perm_group'],$A['perm_members'],$A['perm_anon']);
  1108     if ($access > 0) {
  1109         switch($fieldname) {
  1110             case 'edit':
  1111                 if ($access == 3) {
  1112                     $retval = COM_createLink(
  1113                         $icon_arr['edit'],
  1114                         "{$_CONF['site_admin_url']}/plugins/links/category.php?mode=edit&amp;cid=" . urlencode($A['cid'])
  1115                     );
  1116                 }
  1117                 break;
  1118             case 'access':
  1119                 if ($access == 3) {
  1120                    $retval = $LANG_ACCESS['edit'];
  1121                 } else {
  1122                    $retval = $LANG_ACCESS['readonly'];
  1123                 }
  1124                 break;
  1125             case 'category':
  1126                 $indent = ($A['indent'] - 1) * 20;
  1127                 $cat = COM_createLink($A['category'],
  1128                         "{$_CONF['site_url']}/links/index.php?category="
  1129                         . urlencode($A['cid']));
  1130                 $retval = "<span style=\"padding-left:{$indent}px;\">$cat</span>";
  1131                 break;
  1132             case 'addchild';
  1133                 if ($access == 3) {
  1134                     $retval = COM_createLink(
  1135                         $icon_arr['addchild'],
  1136                         "{$_CONF['site_admin_url']}/plugins/links/category.php?mode=edit&amp;pid=" . urlencode($A['cid'])
  1137                     );
  1138                 }
  1139                 break;
  1140             case 'tid';
  1141                 if ($A['tid'] == 'all') {
  1142                     $retval = $LANG_LINKS_ADMIN[35];
  1143                 } else {
  1144                     $retval = DB_getItem($_TABLES['topics'], 'topic',
  1145                                          "tid = '{$A['tid']}'");
  1146                 }
  1147                 if (empty($retval)) {
  1148                     $retval = $A['tid'];
  1149                 }
  1150                 break;
  1151             default:
  1152                 $retval = $fieldvalue;
  1153                 break;
  1154         }
  1155     }
  1156 
  1157     return $retval;
  1158 }
  1159 
  1160 
  1161 function links_validateUrl($url)
  1162 {
  1163     global $LANG_LINKS_STATUS;
  1164 
  1165     require_once 'HTTP/Request.php';
  1166 
  1167     $retval = '';
  1168 
  1169     $req = new HTTP_Request($url);
  1170     $req->setMethod(HTTP_REQUEST_METHOD_HEAD);
  1171     $req->addHeader('User-Agent', 'Geeklog/' . VERSION);
  1172 
  1173     $response = $req->sendRequest();
  1174     if (PEAR::isError($response)) {
  1175         $retval = $response->getMessage();
  1176     } else {
  1177         $status_code = $req->getResponseCode();
  1178         if (isset($LANG_LINKS_STATUS[$status_code])) {
  1179             $retval = $status_code . ": " . $LANG_LINKS_STATUS[$status_code];
  1180         } else {
  1181             $retval = $LANG_LINKS_STATUS[999];
  1182         }
  1183     }
  1184 
  1185     return $retval;
  1186 }
  1187 
  1188 /**
  1189 * Set template variables
  1190 *
  1191 * @param    string  $templatename   name of template, e.g. 'header'
  1192 * @param    ref     $template       reference of actual template
  1193 * @return   void
  1194 *
  1195 * Note: A plugin should use its name as a prefix for the names of its
  1196 * template variables, e.g. 'links_xxx' and 'lang_links_xxx'.
  1197 * 'button_links' is an exception, as such a variable existed for header.thtml
  1198 * in Geeklog 1.3.11 and earlier, where the Links section was an integral part
  1199 * of Geeklog. It is added here for backward-compatibility.
  1200 *
  1201 */
  1202 function plugin_templatesetvars_links ($templatename, &$template)
  1203 {
  1204     global $LANG_LINKS;
  1205 
  1206     if ($templatename == 'header') {
  1207         $template->set_var ('button_links', $LANG_LINKS[14]);
  1208     }
  1209 }
  1210 
  1211 /**
  1212 * Automatic uninstall function for plugins
  1213 *
  1214 * @return   array
  1215 *
  1216 * This code is automatically uninstalling the plugin.
  1217 * It passes an array to the core code function that removes
  1218 * tables, groups, features and php blocks from the tables.
  1219 * Additionally, this code can perform special actions that cannot be
  1220 * foreseen by the core code (interactions with other plugins for example)
  1221 *
  1222 */
  1223 function plugin_autouninstall_links ()
  1224 {
  1225     $out = array (
  1226         /* give the name of the tables, without $_TABLES[] */
  1227         'tables' => array('links','linksubmission','linkcategories'),
  1228         /* give the full name of the group, as in the db */
  1229         'groups' => array('Links Admin'),
  1230         /* give the full name of the feature, as in the db */
  1231         'features' => array('links.edit', 'links.moderate', 'links.submit'),
  1232         /* give the full name of the block, including 'phpblock_', etc */
  1233         'php_blocks' => array('phpblock_topic_categories', 'phpblock_topic_links'),
  1234         /* give all vars with their name */
  1235         'vars'=> array()
  1236     );
  1237     return $out;
  1238 }
  1239 
  1240 // +--------------------------------------------------------------------------+
  1241 // | Category HTML functions                                                  |
  1242 // | Functions for building select boxes and breadcrumb trails etc.           |
  1243 // +--------------------------------------------------------------------------+
  1244 
  1245 /*
  1246 * Build selection list
  1247 */
  1248 function links_select_box ($access, $sel = '')
  1249 {
  1250     global $_CONF, $LANG_LINKS, $_LI_CONF;
  1251 
  1252     // set root value
  1253     $menu = '<option value="' . $_LI_CONF['root'] . '">' . $LANG_LINKS['root'] . '</option>';
  1254     // get option values
  1255     $list = links_select_box_recursive($menu, $_LI_CONF['root'], $sel, '&nbsp;&nbsp;', $access);
  1256     // return list of options
  1257     return $list;
  1258 }
  1259 
  1260 
  1261 /*
  1262 * Build recursive tree
  1263 */
  1264 function links_select_box_recursive (&$menu, $cid, $sel, $indent, $access)
  1265 {
  1266     global $_CONF, $_TABLES;
  1267 
  1268     $cat = addslashes($cid);
  1269     $sql = "SELECT cid,category
  1270             FROM {$_TABLES['linkcategories']}
  1271             WHERE (pid='{$cat}') " . COM_getPermSQL('AND', 0, $access) . "
  1272             ORDER BY category";
  1273     $query = DB_query($sql);
  1274     while (list($cid, $category) = DB_fetchArray($query)) {
  1275         // set selected item
  1276         if ($cid == $sel) {
  1277             // yes, selected
  1278             $menu .= '<option value="' . htmlspecialchars($cid)
  1279                   . '" selected="selected">' . $indent . $category
  1280                   . '</option>';
  1281         } else {
  1282             // no, not selected
  1283             $menu .= '<option value="' . htmlspecialchars($cid) . '">'
  1284                   . $indent . $category . '</option>';
  1285         }
  1286         // Check and see if this category has any sub categories
  1287         if (DB_count($_TABLES['linkcategories'], 'pid', addslashes($cid)) > 0) {
  1288             // yes, call self
  1289             $dum = links_select_box_recursive ($menu, $cid, $sel,
  1290                         $indent . '&nbsp;&nbsp;', $access);
  1291         }
  1292    }
  1293 
  1294    return $menu;
  1295 }
  1296 
  1297 
  1298 /*
  1299 * Build breadcrumb trail
  1300 *
  1301 * Breadcrumb trail does not use the "root" category in the database: the top
  1302 * level category is set from the language file using $LANG_LINKS['root']
  1303 */
  1304 function links_breadcrumbs($root, $cid)
  1305 {
  1306     global $_CONF, $_TABLES, $LANG_LINKS;
  1307 
  1308     $breadcrumb = '';
  1309     $separator  = ' &gt; ';
  1310 
  1311     $cat = addslashes($cid);
  1312     $c = $cid;
  1313     $pid = '';
  1314     if ($root != $cid) {
  1315         while ($pid != $root) {
  1316             $parent = DB_query("SELECT cid,pid,category FROM {$_TABLES['linkcategories']} WHERE cid='{$cat}'");
  1317             $A = DB_fetchArray($parent);
  1318             if ($cid != $c) {
  1319                 $content = stripslashes($A['category']);
  1320                 $url = $_CONF['site_url'] . '/links/index.php?category='
  1321                                           . urlencode($A['cid']);
  1322                 $breadcrumb = COM_createLink($content, $url) . $separator
  1323                             . $breadcrumb;
  1324             } else {
  1325                 $breadcrumb = '<b>' . $A['category'] . '</b>' . $breadcrumb;
  1326             }
  1327             $pid = $A['pid'];
  1328             $c = $A['pid'];
  1329             $cat = addslashes($c);
  1330         }
  1331     }
  1332 
  1333     $url = $_CONF['site_url'] . '/links/index.php';
  1334     if (empty($breadcrumb)) {
  1335         $breadcrumb = '<b>' . $LANG_LINKS['root'] . '</b>';
  1336     } else {
  1337         $breadcrumb = COM_createLink($LANG_LINKS['root'], $url) . $separator . $breadcrumb;
  1338     }
  1339 
  1340     $breadcrumb = '<span class="links-breadcrumb">' . $LANG_LINKS[126] . ' '
  1341                 . $breadcrumb . '</span>';
  1342 
  1343     return $breadcrumb;
  1344 }
  1345 
  1346 
  1347 
  1348 // +--------------------------------------------------------------------------+
  1349 // | PHP Block functions                                                      |
  1350 // +--------------------------------------------------------------------------+
  1351 
  1352 /**
  1353  * Returns a list of links that belong to categories associated with
  1354  * the current topic
  1355  *
  1356  * Relies on the fact that $topic is set (and sanitized) in lib-common.php
  1357  */
  1358 function phpblock_topic_links()
  1359 {
  1360     global $_CONF, $_TABLES, $LANG_LINKS, $topic;
  1361 
  1362     $retval = '';
  1363 
  1364     if (!empty($topic)) {
  1365         $tid = addslashes($topic);
  1366         $result = DB_query("SELECT l.lid, l.title, l.url, c.cid FROM {$_TABLES['links']} AS l LEFT JOIN {$_TABLES['linkcategories']} AS c ON l.cid=c.cid WHERE c.tid='{$tid}' OR c.tid='all'" . COM_getPermSQL('AND', 0, 2, 'c'));
  1367         $nrows = DB_numRows($result);
  1368         if ($nrows > 0) {
  1369             for ($i = 0; $i < $nrows; $i++) {
  1370                 $A = DB_fetchArray($result);
  1371                 $content = stripslashes($A['title']);
  1372                 $url = COM_buildUrl($_CONF['site_url']
  1373                      . '/links/portal.php?what=link&amp;item=' . $A['lid']);
  1374                 $retval .= COM_createLink($content, $url,
  1375                                           array('title' => $A['url']))
  1376                         . '<br' . XHTML . '>';
  1377             }
  1378         }
  1379     }
  1380 
  1381     return $retval;
  1382 }
  1383 
  1384 
  1385 /**
  1386  * Returns a list of categories that are associated with the current topic
  1387  *
  1388  * Relies on the fact that $topic is set (and sanitized) in lib-common.php
  1389  */
  1390 function phpblock_topic_categories()
  1391 {
  1392     global $_CONF, $_TABLES, $LANG_LINKS, $topic;
  1393 
  1394     $retval = '';
  1395 
  1396     if (!empty($topic)) {
  1397         $tid = addslashes($topic);
  1398         $result = DB_query("SELECT category, cid FROM {$_TABLES['linkcategories']} WHERE tid='{$tid}' OR tid='all'" . COM_getPermSQL ('AND'));
  1399         $nrows = DB_numRows($result);
  1400         if ($nrows > 0) {
  1401             for ($i = 0; $i < $nrows; $i++) {
  1402                 $A = DB_fetchArray($result);
  1403                 $content = stripslashes($A['category']);
  1404                 $url = $_CONF['site_url'] . '/links/index.php?category='
  1405                                           . urlencode($A['cid']);
  1406                 $retval .= COM_createLink($content, $url) . '<br' . XHTML . '>';
  1407             }
  1408         }
  1409     }
  1410 
  1411     return $retval;
  1412 }
  1413 
  1414 /**
  1415 * Return information for a link
  1416 *
  1417 * @param    string  $lid        link ID or '*'
  1418 * @param    string  $what       comma-separated list of properties
  1419 * @param    int     $uid        user ID or 0 = current user
  1420 * @param    array   $options    (reserved for future extensions)
  1421 * @return   mixed               string or array of strings with the information
  1422 *
  1423 */
  1424 function plugin_getiteminfo_links($lid, $what, $uid = 0, $options = array())
  1425 {
  1426     global $_CONF, $_TABLES;
  1427 
  1428     // parse $what to see what we need to pull from the database
  1429     $properties = explode(',', $what);
  1430     $fields = array();
  1431     foreach ($properties as $p) {
  1432         switch ($p) {
  1433         case 'date-modified':
  1434             $fields[] = 'UNIX_TIMESTAMP(date) AS unixdate';
  1435             break;
  1436         case 'description':
  1437         case 'excerpt':
  1438             $fields[] = 'description';
  1439             break;
  1440         case 'id':
  1441             $fields[] = 'lid';
  1442             break;
  1443         case 'title':
  1444             $fields[] = 'title';
  1445             break;
  1446         case 'url':
  1447             // needed for $lid == '*', but also in case we're only requesting
  1448             // the URL (so that $fields isn't emtpy)
  1449             $fields[] = 'lid';
  1450             break;
  1451         default:
  1452             // nothing to do
  1453             break;
  1454         }
  1455     }
  1456 
  1457     $fields = array_unique($fields);
  1458 
  1459     if (count($fields) == 0) {
  1460         $retval = array();
  1461 
  1462         return $retval;
  1463     }
  1464 
  1465     // prepare SQL request
  1466     if ($lid == '*') {
  1467         $where = '';
  1468         $permOp = 'WHERE';
  1469     } else {
  1470         $where = " WHERE lid = '" . addslashes($lid) . "'";
  1471         $permOp = 'AND';
  1472     }
  1473     if ($uid > 0) {
  1474         $permSql = COM_getPermSql($permOp, $uid)
  1475                  . LINKS_getCategorySQL('AND', $uid);
  1476     } else {
  1477         $permSql = COM_getPermSql($permOp) . LINKS_getCategorySQL('AND');
  1478     }
  1479     $sql = "SELECT " . implode(',', $fields)
  1480             . " FROM {$_TABLES['links']}" . $where . $permSql;
  1481     if ($lid != '*') {
  1482         $sql .= ' LIMIT 1';
  1483     }
  1484 
  1485     $result = DB_query($sql);
  1486     $numRows = DB_numRows($result);
  1487 
  1488     $retval = array();
  1489     for ($i = 0; $i < $numRows; $i++) {
  1490         $A = DB_fetchArray($result);
  1491 
  1492         $props = array();
  1493         foreach ($properties as $p) {
  1494             switch ($p) {
  1495             case 'date-modified':
  1496                 $props['date-modified'] = $A['unixdate'];
  1497                 break;
  1498             case 'description':
  1499             case 'excerpt':
  1500                 $props[$p] = stripslashes($A['description']);
  1501                 break;
  1502             case 'id':
  1503                 $props['id'] = $A['lid'];
  1504                 break;
  1505             case 'title':
  1506                 $props['title'] = stripslashes($A['title']);
  1507                 break;
  1508             case 'url':
  1509                 if (empty($A['lid'])) {
  1510                     $props['url'] = COM_buildUrl($_CONF['site_url']
  1511                             . '/links/portal.php?what=link&amp;item=' . $lid);
  1512                 } else {
  1513                     $props['url'] = COM_buildUrl($_CONF['site_url']
  1514                             . '/links/portal.php?what=link&amp;item='
  1515                             . $A['lid']);
  1516                 }
  1517                 break;
  1518             default:
  1519                 // return empty string for unknown properties
  1520                 $props[$p] = '';
  1521                 break;
  1522             }
  1523         }
  1524 
  1525         $mapped = array();
  1526         foreach ($props as $key => $value) {
  1527             if ($lid == '*') {
  1528                 if ($value != '') {
  1529                     $mapped[$key] = $value;
  1530                 }
  1531             } else {
  1532                 $mapped[] = $value;
  1533             }
  1534         }
  1535 
  1536         if ($lid == '*') {
  1537             $retval[] = $mapped;
  1538         } else {
  1539             $retval = $mapped;
  1540             break;
  1541         }
  1542     }
  1543 
  1544     if (($lid != '*') && (count($retval) == 1)) {
  1545         $retval = $retval[0];
  1546     }
  1547 
  1548     return $retval;
  1549 }
  1550 
  1551 /**
  1552 * Return SQL expression to check for allowed categories.
  1553 *
  1554 * Creates part of an SQL expression that can be used to only request links
  1555 * from categories to which the user has access to.
  1556 *
  1557 * Note that this function does SQL requests, so you should cache
  1558 * the resulting SQL expression if you need it more than once.
  1559 *
  1560 * @param    string  $type   part of the SQL expr. e.g. 'WHERE', 'AND'
  1561 * @param    int     $u_id   user id or 0 = current user
  1562 * @param    string  $table  table name if ambiguous (e.g. in JOINs)
  1563 * @return   string          SQL expression string (may be empty)
  1564 * @see      COM_getTopicSQL
  1565 *
  1566 */
  1567 function LINKS_getCategorySQL($type = 'WHERE', $u_id = 0, $table = '')
  1568 {
  1569     global $_TABLES, $_USER, $_GROUPS;
  1570 
  1571     $categorysql = ' ' . $type . ' ';
  1572 
  1573     if (!empty($table)) {
  1574         $table .= '.';
  1575     }
  1576 
  1577     $UserGroups = array();
  1578     if (($u_id <= 0) || (isset($_USER['uid']) && ($u_id == $_USER['uid']))) {
  1579         if (!COM_isAnonUser()) {
  1580             $uid = $_USER['uid'];
  1581         } else {
  1582             $uid = 1;
  1583         }
  1584         $UserGroups = $_GROUPS;
  1585     } else {
  1586         $uid = $u_id;
  1587         $UserGroups = SEC_getUserGroups($uid);
  1588     }
  1589 
  1590     if (empty($UserGroups)) {
  1591         // this shouldn't really happen, but if it does, handle user
  1592         // like an anonymous user
  1593         $uid = 1;
  1594     }
  1595 
  1596     if (SEC_inGroup('Root', $uid)) {
  1597         return '';
  1598     }
  1599 
  1600     $parents = array('root');
  1601     $cids = array();
  1602 
  1603     do {
  1604         $result = DB_query("SELECT cid FROM {$_TABLES['linkcategories']}"
  1605                            . COM_getPermSQL('WHERE', $uid) . " AND pid IN ('"
  1606                            . implode("','", $parents) . "')");
  1607 
  1608         $parents = array();
  1609         while ($C = DB_fetchArray($result)) {
  1610             $parents[] = $C['cid'];
  1611             $cids[] = $C['cid'];
  1612         }
  1613     } while (count($parents) > 0);
  1614 
  1615     if (count($cids) > 0) {
  1616         $categorysql .= "({$table}cid IN ('" . implode("','", $cids) . "'))";
  1617     } else {
  1618         $categorysql .= '0';
  1619     }
  1620 
  1621     return $categorysql;
  1622 }
  1623 
  1624 /**
  1625 * Provide URL of a documentation file
  1626 *
  1627 * @param    string  $file   documentation file being requested, e.g. 'config'
  1628 * @return   mixed           URL or false when not available
  1629 *
  1630 */
  1631 function plugin_getdocumentationurl_links($file)
  1632 {
  1633     global $_CONF;
  1634 
  1635     static $docurl;
  1636 
  1637     switch ($file) {
  1638     case 'index':
  1639     case 'config':
  1640         if (isset($docurl)) {
  1641             $retval = $docurl;
  1642         } else {
  1643             $doclang = COM_getLanguageName();
  1644             $docs = 'docs/' . $doclang . '/links.html';
  1645             if (file_exists($_CONF['path_html'] . $docs)) {
  1646                 $retval = $_CONF['site_url'] . '/' . $docs;
  1647             } else {
  1648                 $retval = $_CONF['site_url'] . '/docs/english/links.html';
  1649             }
  1650             $docurl = $retval;
  1651         }
  1652         break;
  1653 
  1654     default:
  1655         $retval = false;
  1656         break;
  1657     }
  1658 
  1659     return $retval;
  1660 }
  1661 
  1662 ?>