| pierre@0 | 1 <?php | 
| pierre@0 | 2 // $Id: ad.module,v 1.2.2.29.2.83.2.16 2009/02/17 18:56:26 jeremy Exp $ | 
| pierre@0 | 3 | 
| pierre@0 | 4 /** | 
| pierre@0 | 5  * @file | 
| pierre@0 | 6  * An advertising system for Drupal powered websites. | 
| pierre@0 | 7  * | 
| pierre@0 | 8  * Copyright (c) 2005-2009. | 
| pierre@0 | 9  *   Jeremy Andrews <jeremy@tag1consulting.com>. | 
| pierre@0 | 10  */ | 
| pierre@0 | 11 | 
| pierre@0 | 12 | 
| pierre@0 | 13 /** | 
| pierre@0 | 14  * Implementation of hook_theme(). | 
| pierre@0 | 15  */ | 
| pierre@0 | 16 function ad_theme() { | 
| pierre@0 | 17   return array( | 
| pierre@0 | 18     'ad_display' => array( | 
| pierre@0 | 19       'file' => 'ad.module', | 
| pierre@0 | 20       'arguments' => array( | 
| pierre@0 | 21         'group' => NULL, | 
| pierre@0 | 22         'display' => NULL, | 
| pierre@0 | 23         'method' => 'javascript', | 
| pierre@0 | 24       ), | 
| pierre@0 | 25     ), | 
| pierre@0 | 26     'ad_status_display' => array( | 
| pierre@0 | 27       'file' => 'ad.module', | 
| pierre@0 | 28       'arguments' => array( | 
| pierre@0 | 29         'node' => NULL, | 
| pierre@0 | 30       ), | 
| pierre@0 | 31     ), | 
| pierre@0 | 32     'ad_statistics_display' => array( | 
| pierre@0 | 33       'file' => 'ad.pages.inc', | 
| pierre@0 | 34       'arguments' => array( | 
| pierre@0 | 35         'statistics' => NULL, | 
| pierre@0 | 36       ), | 
| pierre@0 | 37     ), | 
| pierre@0 | 38     'node_ad' => array( | 
| pierre@0 | 39       'file' => 'ad.pages.inc', | 
| pierre@0 | 40       'arguments' => array( | 
| pierre@0 | 41         'node' => NULL, | 
| pierre@0 | 42         'yield_form' => TRUE, | 
| pierre@0 | 43       ), | 
| pierre@0 | 44     ), | 
| pierre@0 | 45     'ad_admin_ads' => array( | 
| pierre@0 | 46       'file' => 'ad.admin.inc', | 
| pierre@0 | 47       'arguments' => array( | 
| pierre@0 | 48         'form' => NULL, | 
| pierre@0 | 49       ), | 
| pierre@0 | 50     ), | 
| pierre@0 | 51     'ad_filters' => array( | 
| pierre@0 | 52       'file' => 'ad.admin.inc', | 
| pierre@0 | 53       'arguments' => array( | 
| pierre@0 | 54         'form' => NULL, | 
| pierre@0 | 55       ), | 
| pierre@0 | 56     ), | 
| pierre@0 | 57     'ad_filter_form' => array( | 
| pierre@0 | 58       'file' => 'ad.admin.inc', | 
| pierre@0 | 59       'arguments' => array( | 
| pierre@0 | 60         'form' => NULL, | 
| pierre@0 | 61       ), | 
| pierre@0 | 62     ), | 
| pierre@0 | 63   ); | 
| pierre@0 | 64 }; | 
| pierre@0 | 65 | 
| pierre@0 | 66 /** | 
| pierre@0 | 67  * Use this function to display ads from a specified group. | 
| pierre@0 | 68  * | 
| pierre@0 | 69  * @param $group | 
| pierre@0 | 70  *  The ad group tid to display ads from. | 
| pierre@0 | 71  * @param $quantity | 
| pierre@0 | 72  *  Optionally specify the number of unique ads to display. | 
| pierre@0 | 73  * @param $options | 
| pierre@0 | 74  *  Any number of options from this list:  hostid, nids. | 
| pierre@0 | 75  */ | 
| pierre@0 | 76 function ad($group = FALSE, $quantity = 1, $options = array()) { | 
| pierre@0 | 77   global $base_url; | 
| pierre@0 | 78 | 
| pierre@0 | 79   $adserve = variable_get('adserve', ''); | 
| pierre@0 | 80   $adserveinc = variable_get('adserveinc', ''); | 
| pierre@0 | 81   if (empty($adserve) || empty($adserveinc)) { | 
| pierre@0 | 82     // This is probably the first time ad() has been called. | 
| pierre@0 | 83     _ad_check_installation(); | 
| pierre@0 | 84     $adserve = variable_get('adserve', ''); | 
| pierre@0 | 85     $adserveinc = variable_get('adserveinc', ''); | 
| pierre@0 | 86   } | 
| pierre@0 | 87   if (!file_exists($adserve) || !file_exists($adserveinc)) { | 
| pierre@0 | 88     drupal_set_message(t('Ads cannot be displayed.  The ad module is <a href="@misconfigured">misconfigured</a>, failed to locate the required <em>serve.php</em> ond/or <em>adserve.inc</em> file.', array('@misconfigured' => url('admin/content/ad/configure'))), 'error'); | 
| pierre@0 | 89     _ad_check_installation(); | 
| pierre@0 | 90     return (t('The ad module is <a href="@misconfigured">misconfigured</a>.', array('@misconfigured' => url('admin/content/ad/configure')))); | 
| pierre@0 | 91   } | 
| pierre@0 | 92 | 
| pierre@0 | 93   // Be sure a display method has been chosen. | 
| pierre@0 | 94   if (!isset($options['ad_display'])) { | 
| pierre@0 | 95     $options['ad_display'] = variable_get('ad_display', 'javascript'); | 
| pierre@0 | 96   } | 
| pierre@0 | 97   $options['quantity'] = isset($quantity) ? $quantity : 1; | 
| pierre@0 | 98   if (!isset($options['tids'])) { | 
| pierre@0 | 99     $options['tids'] = $group; | 
| pierre@0 | 100   } | 
| pierre@0 | 101   $options['cache'] = variable_get('ad_cache', 'none'); | 
| pierre@0 | 102 | 
| pierre@0 | 103   switch ($options['ad_display']) { | 
| pierre@0 | 104     case 'raw': | 
| pierre@0 | 105       require_once(drupal_get_path('module', 'ad') .'/adserve.inc'); | 
| pierre@0 | 106       $output = adserve_ad($options); | 
| pierre@0 | 107       break; | 
| pierre@0 | 108     case 'iframe': | 
| pierre@0 | 109     case 'jquery': | 
| pierre@0 | 110       $query['m'] = $options['ad_display']; | 
| pierre@0 | 111       // Fall through... | 
| pierre@0 | 112     case 'javascript': | 
| pierre@0 | 113     default: | 
| pierre@0 | 114       $query['q'] = $quantity; | 
| pierre@0 | 115       if (isset($options['hostid'])) { | 
| pierre@0 | 116         $query['k'] = $options['hostid']; | 
| pierre@0 | 117       } | 
| pierre@0 | 118       // Allow external cache files to define additional display variables. | 
| pierre@0 | 119       if ($options['cache'] != 'none') { | 
| pierre@0 | 120         $query['c'] =  $options['cache']; | 
| pierre@0 | 121         $cache_variables = module_invoke('ad_cache_'. $options['cache'], 'adcacheapi', 'display_variables', array()); | 
| pierre@0 | 122         if (is_array($cache_variables)) { | 
| pierre@0 | 123           foreach ($cache_variables as $key => $value) { | 
| pierre@0 | 124             $query[$key] = $value; | 
| pierre@0 | 125           } | 
| pierre@0 | 126         } | 
| pierre@0 | 127       } | 
| pierre@0 | 128       // Allow ad_type modules to define additional display variables. | 
| pierre@0 | 129       $type_variables = module_invoke_all('adapi', 'display_variables', array()); | 
| pierre@0 | 130       if (is_array($type_variables)) { | 
| pierre@0 | 131         foreach ($type_variables as $key => $value) { | 
| pierre@0 | 132           $query[$key] = $value; | 
| pierre@0 | 133         } | 
| pierre@0 | 134       } | 
| pierre@0 | 135       if (isset($options['nids'])) { | 
| pierre@0 | 136         // Choose ads from the provided list of node Id's. | 
| pierre@0 | 137         $nids = $options['nids']; | 
| pierre@0 | 138         $query['n'] = $nids; | 
| pierre@0 | 139         $group = "nids-$nids"; | 
| pierre@0 | 140       } | 
| pierre@0 | 141       else if (isset($options['tids'])) { | 
| pierre@0 | 142         // Choose ads from the provided list of taxonomy terms. | 
| pierre@0 | 143         $tids = $options['tids']; | 
| pierre@0 | 144         $query['t'] = $tids; | 
| pierre@0 | 145         $group = "tids-$tids"; | 
| pierre@0 | 146       } | 
| pierre@0 | 147       else { | 
| pierre@0 | 148         // Choose ads from the specified group. | 
| pierre@0 | 149         $query['t'] = $group; | 
| pierre@0 | 150         $options['tids'] = $group; | 
| pierre@0 | 151       } | 
| pierre@0 | 152       $src = url($base_url .'/'. $adserve, array('query' => $query)); | 
| pierre@0 | 153       if ($options['ad_display'] == 'iframe') { | 
| pierre@0 | 154         // TODO: We need to know the IFrame size before it is displayed.  This | 
| pierre@0 | 155         // limits the flexibility of what can be displayed in these frames. | 
| pierre@0 | 156         // For now we'll have a global value, later we'll add per-group | 
| pierre@0 | 157         // over-rides. | 
| pierre@0 | 158         $append = 'frameborder="'. variable_get('ad_iframe_frameborder', 0) .'" '; | 
| pierre@0 | 159         $append .= 'scrolling="'. variable_get('ad_iframe_scroll', 'auto') .'" '; | 
| pierre@0 | 160         $append .= 'name="'. $group .'" '; | 
| pierre@0 | 161         if ($height = variable_get('ad_iframe_height', '')) { | 
| pierre@0 | 162           $append .= 'height="'. $height .'" '; | 
| pierre@0 | 163         } | 
| pierre@0 | 164         if ($width = variable_get('ad_iframe_width', '')) { | 
| pierre@0 | 165           $append .= 'width="'. $width .'" '; | 
| pierre@0 | 166         } | 
| pierre@0 | 167         $output = '<iframe src="'. $src ."\" $append></iframe>"; | 
| pierre@0 | 168       } | 
| pierre@0 | 169       else if ($options['ad_display'] == 'jquery') { | 
| pierre@0 | 170         // The theme function uses this to generate a CSS id for jQuery to use. | 
| pierre@0 | 171         $output = $src; | 
| pierre@0 | 172       } | 
| pierre@0 | 173       else { | 
| pierre@0 | 174         $output = '<script type="text/javascript" src="'. $src .'"></script>'; | 
| pierre@0 | 175       } | 
| pierre@0 | 176       break; | 
| pierre@0 | 177   } | 
| pierre@0 | 178 | 
| pierre@0 | 179   if (user_access('show advertisements')) { | 
| pierre@0 | 180     return theme('ad_display', $group, $output, $options['ad_display']); | 
| pierre@0 | 181   } | 
| pierre@0 | 182   else { | 
| pierre@0 | 183     return theme('ad_display', 'none', "<!-- Enable 'show advertisements' permission if you wish to display ads here. -->"); | 
| pierre@0 | 184   } | 
| pierre@0 | 185 } | 
| pierre@0 | 186 | 
| pierre@0 | 187 /** | 
| pierre@0 | 188  * Function to display the actual advertisement to the screen.  Wrap it in a | 
| pierre@0 | 189  * theme function to make it possible to customize in your own theme. | 
| pierre@0 | 190  */ | 
| pierre@0 | 191 function theme_ad_display($group, $display, $method = 'javascript') { | 
| pierre@0 | 192   static $id = 0; | 
| pierre@0 | 193 | 
| pierre@0 | 194   // The naming convention for the id attribute doesn't allow commas. | 
| pierre@0 | 195   $group = preg_replace('/[,]/', '+', $group); | 
| pierre@0 | 196 | 
| pierre@0 | 197   if ($method == 'jquery') { | 
| pierre@0 | 198     drupal_add_js('misc/jquery.js', 'core'); | 
| pierre@0 | 199     return "\n<div class=\"advertisement group-$group\" id=\"group-id-$id\">\n <script type=\"text/javascript\">\n //<!--[CDATA[\n  $(document).ready(function(){ jQuery(\"div#group-id-$id\").load(\"$display\"); });\n //]]>\n </script>\n</div>\n"; | 
| pierre@0 | 200   } | 
| pierre@0 | 201   else { | 
| pierre@0 | 202     return "\n<div class=\"advertisement group-$group\" id=\"group-id-$group\">$display</div>\n"; | 
| pierre@0 | 203   } | 
| pierre@0 | 204 } | 
| pierre@0 | 205 | 
| pierre@0 | 206 /** | 
| pierre@0 | 207  * Update click counter then redirect host to ad's target URL. | 
| pierre@0 | 208  */ | 
| pierre@0 | 209 function ad_redirect($aid, $group, $hostid = 0) { | 
| pierre@0 | 210   global $user; | 
| pierre@0 | 211   if (function_exists('click_filter_status')) { | 
| pierre@0 | 212     $status = click_filter_status($aid, $hostid); | 
| pierre@0 | 213     if ($status == CLICK_VALID) { | 
| pierre@0 | 214       ad_statistics_increment($aid, 'click', $group, $hostid); | 
| pierre@0 | 215     } | 
| pierre@0 | 216   } | 
| pierre@0 | 217   else { | 
| pierre@0 | 218     // We're not filtering clicks, so all clicks are valid. | 
| pierre@0 | 219     ad_statistics_increment($aid, 'click', $group, $hostid); | 
| pierre@0 | 220     $status = 0; | 
| pierre@0 | 221   } | 
| pierre@0 | 222   // Allow source url to be passed in. | 
| pierre@0 | 223   $url = isset($_GET['u']) ? $_GET['u'] : ''; | 
| pierre@0 | 224   if (!isset($url) || !valid_url($url)) { | 
| pierre@0 | 225     $url = referer_uri(); | 
| pierre@0 | 226   } | 
| pierre@0 | 227   db_query("INSERT INTO {ad_clicks} (aid, uid, status, hostname, user_agent, adgroup, hostid, url, timestamp) VALUES (%d, %d, %d, '%s', '%s', '%s', '%s', '%s', %d)", $aid, $user->uid, $status, ip_address(), $_SERVER['HTTP_USER_AGENT'], $group, $hostid, $url, time()); | 
| pierre@0 | 228 | 
| pierre@0 | 229   // Determine where we're supposed to redirect the user. | 
| pierre@0 | 230   $adtype = db_result(db_query('SELECT adtype FROM {ads} WHERE aid = %d', $aid)); | 
| pierre@0 | 231 | 
| pierre@0 | 232   $node->nid = $node->aid = $aid; | 
| pierre@0 | 233   $node->hostid = $hostid; | 
| pierre@0 | 234   $url = module_invoke('ad_'. $adtype, 'adapi', 'redirect', $node); | 
| pierre@0 | 235   if (isset($url)) { | 
| pierre@0 | 236     watchdog('ad', 'Clicked %type ad aid %aid hostid %hostid.', array('%type' => $adtype, '%aid' => $aid, '%hostid' => $hostid)); | 
| pierre@0 | 237     header('Location: '. $url); | 
| pierre@0 | 238   } | 
| pierre@0 | 239   else { | 
| pierre@0 | 240     watchdog('ad', 'Ad redirection failed for aid %aid hostid %hostid, failed to load destination URL. ', array('%aid' => $aid, '%hostid' => $hostid)); | 
| pierre@0 | 241     drupal_goto(''); | 
| pierre@0 | 242   } | 
| pierre@0 | 243 } | 
| pierre@0 | 244 | 
| pierre@0 | 245 /** | 
| pierre@0 | 246  * Ad API Helper Function: | 
| pierre@0 | 247  * Append all necessary attributes to <a> tags. | 
| pierre@0 | 248  */ | 
| pierre@0 | 249 function ad_link_attributes() { | 
| pierre@0 | 250   return array_merge(ad_link_target(TRUE), ad_link_nofollow(TRUE)); | 
| pierre@0 | 251 } | 
| pierre@0 | 252 | 
| pierre@0 | 253 /** | 
| pierre@0 | 254  * Ad API Helper Function: | 
| pierre@0 | 255  * Provide XHTML-strict-compatible target window onclick-handlers based on | 
| pierre@0 | 256  * global configuration. | 
| pierre@0 | 257  */ | 
| pierre@0 | 258 function ad_link_target() { | 
| pierre@0 | 259   switch (variable_get('ad_link_target', '_self')) { | 
| pierre@0 | 260     case '_blank': | 
| pierre@0 | 261       $target = array('onclick' => 'window.open(this.href); return false;'); | 
| pierre@0 | 262       break; | 
| pierre@0 | 263     case '_parent': | 
| pierre@0 | 264       $target = array('onclick' => 'window.parent.location = this.href; return false;'); | 
| pierre@0 | 265       break; | 
| pierre@0 | 266     case '_top': | 
| pierre@0 | 267       $target = array('onclick' => 'window.top.location = this.href; return false;'); | 
| pierre@0 | 268       break; | 
| pierre@0 | 269     default: | 
| pierre@0 | 270       $target = array(); | 
| pierre@0 | 271       break; | 
| pierre@0 | 272   } | 
| pierre@0 | 273   return $target; | 
| pierre@0 | 274 } | 
| pierre@0 | 275 | 
| pierre@0 | 276 /** | 
| pierre@0 | 277  * Ad API Helper Function: | 
| pierre@0 | 278  * Append rel="nofollow" if globally enabled. | 
| pierre@0 | 279  */ | 
| pierre@0 | 280 function ad_link_nofollow() { | 
| pierre@0 | 281   if (variable_get('ad_link_nofollow', 0)) { | 
| pierre@0 | 282     $nofollow = array('rel' => 'nofollow'); | 
| pierre@0 | 283   } | 
| pierre@0 | 284   else { | 
| pierre@0 | 285     $nofollow = array(); | 
| pierre@0 | 286   } | 
| pierre@0 | 287   return $nofollow; | 
| pierre@0 | 288 } | 
| pierre@0 | 289 | 
| pierre@0 | 290 /** | 
| pierre@0 | 291  * Increment action counter. | 
| pierre@0 | 292  */ | 
| pierre@0 | 293 function ad_statistics_increment($aid, $action, $group = NULL, $hostid = NULL) { | 
| pierre@0 | 294   // Update action statistics. | 
| pierre@0 | 295   db_query("UPDATE {ad_statistics} SET count = count + 1 WHERE date = %d AND aid = %d AND action = '%s' AND adgroup = '%s' AND hostid = '%s'", date('YmdH'), $aid, $action, $group, $hostid); | 
| pierre@0 | 296   // If column doesn't already exist, we need to add it. | 
| pierre@0 | 297   if (!db_affected_rows()) { | 
| pierre@0 | 298     db_query("INSERT INTO {ad_statistics} (aid, adgroup, hostid, date, action, count) VALUES(%d, '%s', '%s', %d, '%s', 1)", $aid, $group, $hostid, date('YmdH'), $action); | 
| pierre@0 | 299     // If another process already added this row our INSERT will fail, if so we | 
| pierre@0 | 300     // still need to increment it so we don't loose an action. | 
| pierre@0 | 301     if (!db_affected_rows()) { | 
| pierre@0 | 302       db_query("UPDATE {ad_statistics} SET count = count + 1 WHERE date = %d AND aid = %d AND action = '%s' AND adgroup = '%s' AND hostid = '%s'", date('YmdH'), $aid, $action, $group, $hostid); | 
| pierre@0 | 303     } | 
| pierre@0 | 304   } | 
| pierre@0 | 305 | 
| pierre@0 | 306   $event = array('aid' => $aid, 'action' => $action, 'hostid' => $hostid); | 
| pierre@0 | 307   module_invoke_all('adapi', 'statistics_increment', $event); | 
| pierre@0 | 308 } | 
| pierre@0 | 309 | 
| pierre@0 | 310 function ad_status_array($admin = TRUE) { | 
| pierre@0 | 311   if ($admin) { | 
| pierre@0 | 312     // status options for administrators | 
| pierre@0 | 313     return array( | 
| pierre@0 | 314       'pending' => t('This advertisement is currently waiting for administrative approval.'), | 
| pierre@0 | 315       'approved' => t('This advertisement has been approved and is currently waiting to be administratively activated.'), | 
| pierre@0 | 316       'active' => t('This advertisement is actively being displayed.'), | 
| pierre@0 | 317       'offline' => t('This advertisement has been temporarily disabled by its owner and is not currently being displayed.'), | 
| pierre@0 | 318       'unpublished' => t('This advertisement has been unpublished and is not currently being displayed.'), | 
| pierre@0 | 319       'expired' => t('This advertisement has expired.'), | 
| pierre@0 | 320       'denied' => t('This advertisement was refused by the site administrator, it will not be displayed.')); | 
| pierre@0 | 321   } | 
| pierre@0 | 322   else { | 
| pierre@0 | 323     // status options for advertisement owners | 
| pierre@0 | 324     return array( | 
| pierre@0 | 325       'active' => t('This advertisement is actively being displayed.'), | 
| pierre@0 | 326       'offline' => t('This advertisement has been temporarily disabled and is not currently being displayed.')); | 
| pierre@0 | 327   } | 
| pierre@0 | 328 } | 
| pierre@0 | 329 | 
| pierre@0 | 330 /** | 
| pierre@0 | 331  * Display the status of the currently viewed ad. | 
| pierre@0 | 332  */ | 
| pierre@0 | 333 function theme_ad_status_display($node) { | 
| pierre@0 | 334   $status_array = ad_status_array(); | 
| pierre@0 | 335   $output  = '<div class="adstatus">'; | 
| pierre@0 | 336   $output .= '<p>'. t($status_array[$node->adstatus]) .'</p>'; | 
| pierre@0 | 337   switch ($node->adstatus) { | 
| pierre@0 | 338     case 'approved': | 
| pierre@0 | 339       if ($node->autoactivate) { | 
| pierre@0 | 340         $output .= '<p>'. t('This advertisement will be automatically activated on %timestamp, in %time.', array('%timestamp' => format_date($node->autoactivate, 'large'), '%time' => format_interval($node->autoactivate - time()))) .'</p>'; | 
| pierre@0 | 341       } | 
| pierre@0 | 342       break; | 
| pierre@0 | 343     case 'active': | 
| pierre@0 | 344       $activated = db_result(db_query("SELECT activated FROM {ads} WHERE aid = %d", $node->nid)); | 
| pierre@0 | 345       if ($activated) { | 
| pierre@0 | 346         $output .= '<p>'. t('This advertisement has been active since %date.', array('%date' => format_date($activated, 'large'))) .'</p>'; | 
| pierre@0 | 347       } | 
| pierre@0 | 348       if ($node->autoexpire) { | 
| pierre@0 | 349         $output .= '<p>'. t('This advertisement will expire on %timestamp, in %time.', array('%timestamp' => format_date($node->autoexpire, 'large'), '%time' => format_interval($node->autoexpire - time()))) .'</p>'; | 
| pierre@0 | 350       } | 
| pierre@0 | 351       if ($node->maxviews) { | 
| pierre@0 | 352         $views = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d", $node->nid, date('YmdH', $node->activated))); | 
| pierre@0 | 353         $output .= '<p>'. t('This advertisement will expire after %left more impressions.', array('%left' => $node->maxviews - $views)) .'</p>'; | 
| pierre@0 | 354       } | 
| pierre@0 | 355       if ($node->maxclicks) { | 
| pierre@0 | 356         $clicks = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d", $node->nid, date('YmdH', $node->activated))); | 
| pierre@0 | 357         $output .= '<p>'. t('This advertisement will expire after %left more clicks.', array('%left' => $node->maxclicks - $clicks)) .'</p>'; | 
| pierre@0 | 358       } | 
| pierre@0 | 359       break; | 
| pierre@0 | 360     case 'expired': | 
| pierre@0 | 361       $expired = db_result(db_query("SELECT expired FROM {ads} WHERE aid = %d", $node->nid)); | 
| pierre@0 | 362       if ($expired) { | 
| pierre@0 | 363         $output .= '<p>'. t('This advertisement expired %date.', array('%date' => format_date($expired, 'large'))) .'</p>'; | 
| pierre@0 | 364       } | 
| pierre@0 | 365       break; | 
| pierre@0 | 366   } | 
| pierre@0 | 367   $output .= '</div>'; | 
| pierre@0 | 368   return theme('box', t('Status'), $output); | 
| pierre@0 | 369 } | 
| pierre@0 | 370 | 
| pierre@0 | 371 /** | 
| pierre@0 | 372  * Implementation of hook_help(). | 
| pierre@0 | 373  */ | 
| pierre@0 | 374 function ad_help($path, $arg) { | 
| pierre@0 | 375   $output = ''; | 
| pierre@0 | 376   switch ($path) { | 
| pierre@0 | 377     case 'admin/help#ad': | 
| pierre@0 | 378       $output = '<p>'. t('The ad module provides a complete advertising system for Drupal powered websites.  It does this through an API that allow other modules to handle various types of advertising content.  For example, if enabled together with the ad_image module you will be able to display image based advertisements such as banner ads.') .'</p>'; | 
| pierre@0 | 379       break; | 
| pierre@0 | 380     case 'node/add/ad': | 
| pierre@0 | 381       $output = '<p>'. t('Advertisements can be randomly displayed to visitors of your website.') .'</p>'; | 
| pierre@0 | 382       break; | 
| pierre@0 | 383   } | 
| pierre@0 | 384   return $output; | 
| pierre@0 | 385 } | 
| pierre@0 | 386 | 
| pierre@0 | 387 /** | 
| pierre@0 | 388  * Implementation of hook_cron(). | 
| pierre@0 | 389  */ | 
| pierre@0 | 390 function ad_cron() { | 
| pierre@0 | 391   if (time() - variable_get('ad_cron_timestamp', 0) >= 60) { | 
| pierre@0 | 392     // Locate ads that need to be activated or expired. | 
| pierre@0 | 393     $result = db_query('SELECT aid, adstatus, adtype, autoactivate, autoactivated, autoexpire, autoexpired FROM {ads} WHERE autoactivate <> 0 OR autoexpire <> 0'); | 
| pierre@0 | 394     while ($ad = db_fetch_object($result)) { | 
| pierre@0 | 395       switch ($ad->adstatus) { | 
| pierre@0 | 396         case 'approved': { | 
| pierre@0 | 397           // See if this ad is ready to be activated. | 
| pierre@0 | 398           if ($ad->autoactivate && $ad->autoactivate <= time()) { | 
| pierre@0 | 399             $node = node_load($ad->aid); | 
| pierre@0 | 400 | 
| pierre@0 | 401             // Activate the ad. | 
| pierre@0 | 402             db_query("UPDATE {ads} SET adstatus = 'active', autoactivate = 0, autoactivated = %d, activated = %d WHERE aid = %d", time(), time(), $ad->aid); | 
| pierre@0 | 403             ad_statistics_increment($ad->aid, 'autoactivated'); | 
| pierre@0 | 404             ad_statistics_increment($ad->aid, 'active'); | 
| pierre@0 | 405 | 
| pierre@0 | 406             watchdog('ad', 'Automatically activated ad %title with nid %nid.', array('%title' => $node->title, '%nid' => $node->nid)); | 
| pierre@0 | 407 | 
| pierre@0 | 408             // Allow modules to do special processing to automatically | 
| pierre@0 | 409             // activated advertisements. | 
| pierre@0 | 410             module_invoke('ad_'. $ad->adtype, 'adapi', 'autoactivate', $node); | 
| pierre@0 | 411           } | 
| pierre@0 | 412           else if (!$ad->autoactivate) { | 
| pierre@0 | 413             // Once daily warn that there's an ad stuck in approved state. | 
| pierre@0 | 414             if (time() - variable_get("ad_autoactivate_warning_$ad->aid", 0) >= 8600) { | 
| pierre@0 | 415               watchdog('ad', 'Warning: ad %title with nid %nid in approved state has no autoactivate date set.', array('%title' => $node->title, '%nid' => $node->nid)); | 
| pierre@0 | 416               variable_set("ad_autoactivate_warning_$ad->aid", time()); | 
| pierre@0 | 417             } | 
| pierre@0 | 418           } | 
| pierre@0 | 419           break; | 
| pierre@0 | 420         } | 
| pierre@0 | 421         case 'active': { | 
| pierre@0 | 422           // See if this ad is ready to be activated. | 
| pierre@0 | 423           if ($ad->autoexpire && $ad->autoexpire <= time()) { | 
| pierre@0 | 424             $node = node_load($ad->aid); | 
| pierre@0 | 425 | 
| pierre@0 | 426             // Expire the ad. | 
| pierre@0 | 427             db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $ad->aid); | 
| pierre@0 | 428             ad_statistics_increment($ad->aid, 'autoexpired'); | 
| pierre@0 | 429             ad_statistics_increment($ad->aid, 'expired'); | 
| pierre@0 | 430 | 
| pierre@0 | 431             watchdog('ad', 'Automatically expired ad %title with nid %nid.', array('%title' => $node->title, '%nid' => $node->nid)); | 
| pierre@0 | 432 | 
| pierre@0 | 433             // Allow modules to do special processing to automatically | 
| pierre@0 | 434             // activated advertisements. | 
| pierre@0 | 435             module_invoke('ad_'. $ad->adtype, 'adapi', 'autoexpire', $node); | 
| pierre@0 | 436           } | 
| pierre@0 | 437           else if (!$ad->autoexpire) { | 
| pierre@0 | 438             // Ad is already activated, but has autoactivate timestamp set. | 
| pierre@0 | 439             db_query("UPDATE {ads} SET autoactivate = 0 WHERE aid = %d", $ad->aid); | 
| pierre@0 | 440           } | 
| pierre@0 | 441           break; | 
| pierre@0 | 442         } | 
| pierre@0 | 443         default: | 
| pierre@0 | 444           $node = node_load($ad->aid); | 
| pierre@0 | 445           db_query('UPDATE {ads} SET autoactivate = 0, autoexpire = 0 WHERE aid = %d', $ad->aid); | 
| pierre@0 | 446           watchdog('ad', 'Warning: reset %type timestamp on advertisement %title with nid %nid because it is in %state state.', array('%title' => $node->title, '%nid' => $node->nid, '%type' => $ad->autoactivate ? 'autoactivate' : 'autoexpire', '%state' => $ad->adstatus)); | 
| pierre@0 | 447       } | 
| pierre@0 | 448     } | 
| pierre@0 | 449     variable_set('ad_cron_timestamp', time()); | 
| pierre@0 | 450   } | 
| pierre@0 | 451 } | 
| pierre@0 | 452 | 
| pierre@0 | 453 /** | 
| pierre@0 | 454  * Implementation of hook_perm(). | 
| pierre@0 | 455  */ | 
| pierre@0 | 456 function ad_perm() { | 
| pierre@0 | 457   return array('administer advertisements', | 
| pierre@0 | 458                 'create advertisements', | 
| pierre@0 | 459                 'edit own advertisements', | 
| pierre@0 | 460                 'show advertisements'); | 
| pierre@0 | 461 } | 
| pierre@0 | 462 | 
| pierre@0 | 463 /** | 
| pierre@0 | 464  * Implementation of hook_node_info(). | 
| pierre@0 | 465  */ | 
| pierre@0 | 466 function ad_node_info() { | 
| pierre@0 | 467   $items['ad'] = array( | 
| pierre@0 | 468     'name' => t('Advertisement'), | 
| pierre@0 | 469     'module' => 'ad', | 
| pierre@0 | 470     'description' => t('Advertisements can be randomly displayed to visitors of your website.'), | 
| pierre@0 | 471   ); | 
| pierre@0 | 472 | 
| pierre@0 | 473   $adtypes = ad_get_types('data'); | 
| pierre@0 | 474   // New 'type' notation returns everything we need to define content type | 
| pierre@0 | 475   foreach ($adtypes as $type => $data) { | 
| pierre@0 | 476     $items['ad/'. $type] = $data; | 
| pierre@0 | 477   } | 
| pierre@0 | 478   return $items; | 
| pierre@0 | 479 } | 
| pierre@0 | 480 | 
| pierre@0 | 481 /** | 
| pierre@0 | 482  * Implementation of hook_access(). | 
| pierre@0 | 483  */ | 
| pierre@0 | 484 function ad_access($op, $node, $account) { | 
| pierre@0 | 485   if ($op == 'create') { | 
| pierre@0 | 486     return user_access('create advertisements', $account); | 
| pierre@0 | 487   } | 
| pierre@0 | 488 | 
| pierre@0 | 489   if ($op == 'update' || $op == 'delete') { | 
| pierre@0 | 490     return (user_access('administer advertisements', $account) || | 
| pierre@0 | 491            (module_exists('ad_owners') && ad_is_owner($node->nid) && user_access('edit own advertisements', $account))); | 
| pierre@0 | 492   } | 
| pierre@0 | 493 } | 
| pierre@0 | 494 | 
| pierre@0 | 495 /** | 
| pierre@0 | 496  * Implementation of hook_form(). | 
| pierre@0 | 497  */ | 
| pierre@0 | 498 function ad_form($node, &$form_state) { | 
| pierre@0 | 499   $form = array(); | 
| pierre@0 | 500 | 
| pierre@0 | 501   $type = arg(3); | 
| pierre@0 | 502   if (function_exists('ad_'. $type .'_display_ad')) { | 
| pierre@0 | 503     $adtype = $type; | 
| pierre@0 | 504   } | 
| pierre@0 | 505   else { | 
| pierre@0 | 506     $adtype = isset($node->adtype) ? $node->adtype : ''; | 
| pierre@0 | 507   } | 
| pierre@0 | 508 | 
| pierre@0 | 509   $form['aid'] = array( | 
| pierre@0 | 510     '#type' => 'value', | 
| pierre@0 | 511     '#value' => isset($node->nid) ? $node->nid : 0, | 
| pierre@0 | 512   ); | 
| pierre@0 | 513 | 
| pierre@0 | 514   $form['title'] = array( | 
| pierre@0 | 515     '#type' => 'textfield', | 
| pierre@0 | 516     '#title' => t('Title'), | 
| pierre@0 | 517     '#required' => TRUE, | 
| pierre@0 | 518     '#default_value' => isset($node->title) ? $node->title : '', | 
| pierre@0 | 519   ); | 
| pierre@0 | 520   $form['body_filter']['body'] = array( | 
| pierre@0 | 521     '#type' => 'textarea', | 
| pierre@0 | 522     '#title' => t('Description'), | 
| pierre@0 | 523     '#default_value' => isset($node->body) ? $node->body : '', | 
| pierre@0 | 524     '#rows' => 3 | 
| pierre@0 | 525   ); | 
| pierre@0 | 526   $form['body_filter']['format'] = filter_form($node->format); | 
| pierre@0 | 527 | 
| pierre@0 | 528   // determine the current ad type | 
| pierre@0 | 529   if (!isset($adtype)) { | 
| pierre@0 | 530     $adtypes = ad_get_types(); | 
| pierre@0 | 531     if (sizeof($adtypes) == 1) { | 
| pierre@0 | 532       $adtype = key($adtypes); | 
| pierre@0 | 533     } | 
| pierre@0 | 534     else if (!sizeof($adtypes)) { | 
| pierre@0 | 535       drupal_set_message(t('At least one ad type module must be enabled before you can create advertisements.  For example, try <a href="!url">enabling</a> the ad_text or ad_image module.', array('!url' => url('admin/build/modules'))), 'error'); | 
| pierre@0 | 536     } | 
| pierre@0 | 537   } | 
| pierre@0 | 538 | 
| pierre@0 | 539   // display type-specific options | 
| pierre@0 | 540   if (isset($adtype)) { | 
| pierre@0 | 541     $elements = module_invoke('ad_'. $adtype, 'adapi', 'form', $node); | 
| pierre@0 | 542     if (is_array($elements)) { | 
| pierre@0 | 543       foreach ($elements as $element => $values) { | 
| pierre@0 | 544         $form[$element] = $values; | 
| pierre@0 | 545       } | 
| pierre@0 | 546     } | 
| pierre@0 | 547     $form['adtype'] = array( | 
| pierre@0 | 548       '#type' => 'hidden', | 
| pierre@0 | 549       '#value' => $adtype, | 
| pierre@0 | 550     ); | 
| pierre@0 | 551   } | 
| pierre@0 | 552 | 
| pierre@0 | 553   if (user_access('administer advertisements')) { | 
| pierre@0 | 554     // admins can set any status on advertisements | 
| pierre@0 | 555     $form['adstatus'] = array( | 
| pierre@0 | 556       '#type' => 'fieldset', | 
| pierre@0 | 557       '#title' => t('Status'), | 
| pierre@0 | 558       '#collapsible' => TRUE | 
| pierre@0 | 559     ); | 
| pierre@0 | 560     foreach (ad_status_array() as $status => $description) { | 
| pierre@0 | 561       $form['adstatus']["ad$status"] = array( | 
| pierre@0 | 562         '#type' => 'radio', | 
| pierre@0 | 563         '#title' => t($status), | 
| pierre@0 | 564         '#return_value' => $status, | 
| pierre@0 | 565         '#default_value' => isset($node->adstatus) ? $node->adstatus : 'pending', | 
| pierre@0 | 566         '#description' => $description, | 
| pierre@0 | 567         '#parents' => array('adstatus') | 
| pierre@0 | 568       ); | 
| pierre@0 | 569     } | 
| pierre@0 | 570   } | 
| pierre@0 | 571   else if (ad_adaccess($node, 'manage status')) { | 
| pierre@0 | 572     if (!$node->adstatus || $node->adstatus == 'pending') { | 
| pierre@0 | 573       $adstatus = ad_status_array(); | 
| pierre@0 | 574       $node->adstatus = 'pending'; | 
| pierre@0 | 575       $form['adstatus'] = array( | 
| pierre@0 | 576         '#type' => 'fieldset', | 
| pierre@0 | 577         '#title' => t('Status'), | 
| pierre@0 | 578         '#collapsible' => TRUE | 
| pierre@0 | 579       ); | 
| pierre@0 | 580       $form['adstatus']['display'] = array( | 
| pierre@0 | 581         '#type' => 'markup', | 
| pierre@0 | 582         '#value' => '<p><strong>'. t('Status') .':</strong> '. t($node->adstatus) .'<br />'. t($adstatus[$node->adstatus]), | 
| pierre@0 | 583       ); | 
| pierre@0 | 584       $form['adstatus']['adpending'] = array( | 
| pierre@0 | 585         '#type' => 'value', | 
| pierre@0 | 586         '#value' => $node->adstatus | 
| pierre@0 | 587       ); | 
| pierre@0 | 588     } | 
| pierre@0 | 589     else { | 
| pierre@0 | 590       $adstatus = ad_status_array(FALSE); | 
| pierre@0 | 591       // display status options | 
| pierre@0 | 592       $form['adstatus'] = array( | 
| pierre@0 | 593         '#type' => 'fieldset', | 
| pierre@0 | 594         '#title' => t('Status'), | 
| pierre@0 | 595         '#collapsible' => TRUE | 
| pierre@0 | 596       ); | 
| pierre@0 | 597       foreach ($adstatus as $status => $description) { | 
| pierre@0 | 598         $form['adstatus']["ad$status"] = array( | 
| pierre@0 | 599           '#type' => 'radio', | 
| pierre@0 | 600           '#title' => t($status), | 
| pierre@0 | 601           '#return_value' => $status, | 
| pierre@0 | 602           '#default_value' => $node->adstatus ? $node->adstatus : 'pending', | 
| pierre@0 | 603           '#description' => $description, | 
| pierre@0 | 604           '#parents' => array("adstatus") | 
| pierre@0 | 605         ); | 
| pierre@0 | 606       } | 
| pierre@0 | 607     } | 
| pierre@0 | 608   } | 
| pierre@0 | 609   else { | 
| pierre@0 | 610     $adstatus = ad_status_array(); | 
| pierre@0 | 611     if (!isset($node->adstatus)) { | 
| pierre@0 | 612       $node->adstatus = 'pending'; | 
| pierre@0 | 613     } | 
| pierre@0 | 614     $form['ad_adstatus'] = array( | 
| pierre@0 | 615       '#type' => 'fieldset', | 
| pierre@0 | 616       '#title' => t('Status'), | 
| pierre@0 | 617       '#collapsible' => TRUE | 
| pierre@0 | 618     ); | 
| pierre@0 | 619     $form['ad_adstatus']['adstatus_display'] = array( | 
| pierre@0 | 620       '#type' => 'markup', | 
| pierre@0 | 621       '#value' => '<p><strong>'. t('Status') .':</strong> '. t($node->adstatus) .'<br />'. t($adstatus[$node->adstatus]), | 
| pierre@0 | 622     ); | 
| pierre@0 | 623     $form['adstatus'] = array( | 
| pierre@0 | 624       '#type' => 'value', | 
| pierre@0 | 625       '#value' => $node->adstatus | 
| pierre@0 | 626     ); | 
| pierre@0 | 627   } | 
| pierre@0 | 628 | 
| pierre@0 | 629   // display scheduling options | 
| pierre@0 | 630   $form['schedule'] = array( | 
| pierre@0 | 631     '#type' => 'fieldset', | 
| pierre@0 | 632     '#title' => t('Scheduling'), | 
| pierre@0 | 633     '#collapsible' => TRUE, | 
| pierre@0 | 634     // Collapse if there isn't any scheduling data set. | 
| pierre@0 | 635     '#collapsed' => ( | 
| pierre@0 | 636       isset($node->autoactivate) || | 
| pierre@0 | 637       isset($form_state['values']['autoactivate']) || | 
| pierre@0 | 638       isset($node->autoexpire) || | 
| pierre@0 | 639       isset($form_state['values']['autoexpire']) || | 
| pierre@0 | 640       isset($node->maxviews) || | 
| pierre@0 | 641       isset($form_state['values']['maxviews']) || | 
| pierre@0 | 642       isset($node->maxclicks) || | 
| pierre@0 | 643       isset($form_state['values']['maxclicks'])) | 
| pierre@0 | 644       ? FALSE : TRUE, | 
| pierre@0 | 645   ); | 
| pierre@0 | 646 | 
| pierre@0 | 647   if (ad_adaccess($node, 'manage status')) { | 
| pierre@0 | 648     $form['schedule']['current'] = array( | 
| pierre@0 | 649       '#type' => 'markup', | 
| pierre@0 | 650       '#prefix' => '<div>', | 
| pierre@0 | 651       '#suffix' => '</div>', | 
| pierre@0 | 652       '#value' => t('The current date and time is "%date".', array('%date' => format_date(time(), 'custom', 'F j, Y H:i'))) | 
| pierre@0 | 653     ); | 
| pierre@0 | 654     $form['schedule']['autoactivate'] = array( | 
| pierre@0 | 655       '#type' => 'textfield', | 
| pierre@0 | 656       '#title' => t('Automatically activate ad'), | 
| pierre@0 | 657       '#required' => FALSE, | 
| pierre@0 | 658       '#default_value' => isset($node->autoactivate) && $node->autoactivate > 0 ? format_date((int)$node->autoactivate, 'custom', 'F j, Y H:i') : 0, | 
| pierre@0 | 659       '#description' => t('You can specify a date and time for this advertisement to be automatically activated.  The advertisement needs to be in an <em>approved</em> state before it can be automatically activated.  If you prefer to activate the advertisement immediately, leave this field empty.') | 
| pierre@0 | 660     ); | 
| pierre@0 | 661   } | 
| pierre@0 | 662 | 
| pierre@0 | 663   if (user_access('administer advertisements')) { | 
| pierre@0 | 664     // admins can expire advertisements | 
| pierre@0 | 665     $form['schedule']['autoexpire'] = array( | 
| pierre@0 | 666       '#type' => 'textfield', | 
| pierre@0 | 667       '#title' => t('Automatically expire ad'), | 
| pierre@0 | 668       '#required' => FALSE, | 
| pierre@0 | 669       '#default_value' => isset($node->autoexpire) && $node->autoexpire > 0 ? format_date((int)$node->autoexpire, 'custom', 'F j, Y H:i') : 0, | 
| pierre@0 | 670       '#description' => t('You can specify a date and time for this advertisement to be automatically expired.  If you don\'t want the advertisement to expire, leave this field empty.') | 
| pierre@0 | 671     ); | 
| pierre@0 | 672     $form['schedule']['maxviews'] = array( | 
| pierre@0 | 673       '#type' => 'textfield', | 
| pierre@0 | 674       '#title' => t('Maximum impressions'), | 
| pierre@0 | 675       '#required' => FALSE, | 
| pierre@0 | 676       '#size' => 10, | 
| pierre@0 | 677       '#maxlength' => 11, | 
| pierre@0 | 678       '#default_value' => isset($node->maxviews) ? $node->maxviews : 0, | 
| pierre@0 | 679       '#description' => t('You can specify the maximum number of times this advertisement should be displayed, after which it will be automatically expired.  If you don\'t want this advertisement to expire after a certain number of impressions, leave this field set to %zero.', array('%zero' => '0')), | 
| pierre@0 | 680     ); | 
| pierre@0 | 681     $form['schedule']['maxclicks'] = array( | 
| pierre@0 | 682       '#type' => 'textfield', | 
| pierre@0 | 683       '#title' => t('Maximum clicks'), | 
| pierre@0 | 684       '#required' => FALSE, | 
| pierre@0 | 685       '#size' => 10, | 
| pierre@0 | 686       '#maxlength' => 11, | 
| pierre@0 | 687       '#default_value' => isset($node->maxclicks) ? $node->maxclicks : 0, | 
| pierre@0 | 688       '#description' => t('You can specify the maximum number of times this advertisement should be clicked, after which it will be automatically expired.  If you don\'t want this advertisement to expire after a certain number of clicks leave this field set to %zero.', array('%zero' => '0')), | 
| pierre@0 | 689     ); | 
| pierre@0 | 690   } | 
| pierre@0 | 691   else { | 
| pierre@0 | 692     // display expiration time | 
| pierre@0 | 693     $form['schedule']['autoexpire_display'] = array( | 
| pierre@0 | 694       '#type' => 'markup', | 
| pierre@0 | 695       '#prefix' => '<div>', | 
| pierre@0 | 696       '#suffix' => '</div>', | 
| pierre@0 | 697       '#value' => theme('ad_status_display', $node), | 
| pierre@0 | 698     ); | 
| pierre@0 | 699     $form['schedule']['autoexpire'] = array( | 
| pierre@0 | 700       '#type' => 'hidden', | 
| pierre@0 | 701       '#value' => isset($node->autoexpire) ? $node->autoexpire : 0, | 
| pierre@0 | 702     ); | 
| pierre@0 | 703   } | 
| pierre@0 | 704 | 
| pierre@0 | 705   return $form; | 
| pierre@0 | 706 } | 
| pierre@0 | 707 | 
| pierre@0 | 708 /** | 
| pierre@0 | 709  * Implementation of hook_form_alter(). | 
| pierre@0 | 710  */ | 
| pierre@0 | 711 function ad_form_alter(&$form, &$form_state, $form_id) { | 
| pierre@0 | 712   if ($form_id == 'ad_node_form') { | 
| pierre@0 | 713     $adtypes = ad_get_types('data'); | 
| pierre@0 | 714     if (isset($form['adtype']) && isset($form['adtype']['#value'])) { | 
| pierre@0 | 715       $adtype = $form['adtype']['#value']; | 
| pierre@0 | 716       if (isset($adtypes[$adtype])) { | 
| pierre@0 | 717         // Valid advertisement type selected. | 
| pierre@0 | 718         return; | 
| pierre@0 | 719       } | 
| pierre@0 | 720     } | 
| pierre@0 | 721     if (sizeof($adtypes) == 1) { | 
| pierre@0 | 722       // Auto select the appropriate advertisement type. | 
| pierre@0 | 723       drupal_goto('node/add/ad/'. key($adtypes)); | 
| pierre@0 | 724     } | 
| pierre@0 | 725     else { | 
| pierre@0 | 726       foreach ($adtypes as $key => $adtype) { | 
| pierre@0 | 727         $out = '<dt>'. l($adtype['name'], "node/add/ad/$key", array('title' => t('Add a !key', array('!key' => $adtype['name'])))) .'</dt>'; | 
| pierre@0 | 728         $out .= '<dd>'. $adtype['description'] .'</dd>'; | 
| pierre@0 | 729         $item[$key] = $out; | 
| pierre@0 | 730       } | 
| pierre@0 | 731       if (isset($item)) { | 
| pierre@0 | 732         $output = t('Choose from the following advertisement types:'); | 
| pierre@0 | 733         $output .= '<dl>'. implode('', $item) .'</dl>'; | 
| pierre@0 | 734       } | 
| pierre@0 | 735       else { | 
| pierre@0 | 736         $output = t('You are not allowed to create advertisements.'); | 
| pierre@0 | 737       } | 
| pierre@0 | 738 | 
| pierre@0 | 739       $form = array(); | 
| pierre@0 | 740       $form['select'] = array( | 
| pierre@0 | 741         '#value' => $output, | 
| pierre@0 | 742       ); | 
| pierre@0 | 743       $form['#tree'] = FALSE; | 
| pierre@0 | 744       $form['#programmed'] = FALSE; | 
| pierre@0 | 745     } | 
| pierre@0 | 746   } | 
| pierre@0 | 747   if ($form_id == 'taxonomy_form_vocabulary') { | 
| pierre@0 | 748     // Remove taxonomy form options not applicable for ad groups. | 
| pierre@0 | 749     if ($form['vid']['#value'] == _ad_get_vid()) { | 
| pierre@0 | 750       $form['help_ad_vocab'] = array( | 
| pierre@0 | 751         '#value' => t('This vocabulary was automatically created for use by the ad module.  Only applicable options are available.'), | 
| pierre@0 | 752         '#weight' => -1 | 
| pierre@0 | 753       ); | 
| pierre@0 | 754       $form['nodes']['ad'] = array( | 
| pierre@0 | 755         '#type' => 'checkbox', | 
| pierre@0 | 756         '#title' => t('ad group'), | 
| pierre@0 | 757         '#value' => 1, | 
| pierre@0 | 758         '#attributes' => array('disabled' => ''), | 
| pierre@0 | 759         '#description' => t('Type %type is required to use this vocabulary.', array('%type' => t('ad group'))) | 
| pierre@0 | 760       ); | 
| pierre@0 | 761       $form['tags']['#description'] = t('If enabled, ads are categorized by typing ad group names instead of choosing them from a list.'); | 
| pierre@0 | 762       $form['multiple']['#description'] = t('If enabled, allows ads to have more than one ad group (always true for free tagging).'); | 
| pierre@0 | 763       $form['required']['#description'] = t('If enabled, every ad <strong>must</strong> be assigned to at least one ad group.'); | 
| pierre@0 | 764       $form['hierarchy'] = array( | 
| pierre@0 | 765         '#type' => 'value', | 
| pierre@0 | 766         '#value' => 0 | 
| pierre@0 | 767       ); | 
| pierre@0 | 768       unset($form['relations']); | 
| pierre@0 | 769     } | 
| pierre@0 | 770     else { | 
| pierre@0 | 771       unset($form['nodes']['ad']); | 
| pierre@0 | 772     } | 
| pierre@0 | 773   } | 
| pierre@0 | 774   else if ($form_id == 'taxonomy_form_term') { | 
| pierre@0 | 775     if ($form['vid']['#value'] == _ad_get_vid()) { | 
| pierre@0 | 776       $form['name']['#title'] = t('Ad group name'); | 
| pierre@0 | 777       $form['name']['#description'] = t('The name for this ad group.  Example: "Linux".'); | 
| pierre@0 | 778       $form['description']['#description'] = t('A description of the ad group.'); | 
| pierre@0 | 779       $form['description']['#required'] = TRUE; | 
| pierre@0 | 780       $form['weight']['#description'] = t('In listings, the heavier ad groups will sink and the lighter ad groups will be positioned nearer the top.'); | 
| pierre@0 | 781       unset($form['synonyms']); | 
| pierre@0 | 782     } | 
| pierre@0 | 783   } | 
| pierre@0 | 784 } | 
| pierre@0 | 785 | 
| pierre@0 | 786 /** | 
| pierre@0 | 787  * Submit handler for global settings of all ad types. | 
| pierre@0 | 788  * | 
| pierre@0 | 789  * @see ad_form_alter() | 
| pierre@0 | 790  */ | 
| pierre@0 | 791 function ad_global_settings_submit($form, &$form_state) { | 
| pierre@0 | 792   variable_set('ad_'. $form_state['values']['adtype'] .'_default_permissions', $form_state['values']['default_permissions']); | 
| pierre@0 | 793   unset($form_state['values']['adtype'], $form_state['values']['default_permissions']); | 
| pierre@0 | 794 } | 
| pierre@0 | 795 | 
| pierre@0 | 796 /** | 
| pierre@0 | 797  * Implementation of hook_nodeapi(). | 
| pierre@0 | 798  */ | 
| pierre@0 | 799 function ad_nodeapi(&$node, $op, $teaser, $page) { | 
| pierre@0 | 800   global $user; | 
| pierre@0 | 801 | 
| pierre@0 | 802   switch ($op) { | 
| pierre@0 | 803 | 
| pierre@0 | 804     case 'load': | 
| pierre@0 | 805       $ad = db_fetch_array(db_query('SELECT * FROM {ads} WHERE aid = %d', $node->nid)); | 
| pierre@0 | 806       $merge = array_merge((array)$node, (array)$ad); | 
| pierre@0 | 807       $adtype = module_invoke('ad_'. $ad['adtype'], 'adapi', 'load', $merge); | 
| pierre@0 | 808       if (is_array($adtype)) { | 
| pierre@0 | 809         return array_merge($ad, $adtype); | 
| pierre@0 | 810       } | 
| pierre@0 | 811       else { | 
| pierre@0 | 812         return $ad; | 
| pierre@0 | 813       } | 
| pierre@0 | 814       break; | 
| pierre@0 | 815 | 
| pierre@0 | 816     case 'insert': | 
| pierre@0 | 817       if (isset($node->adtype)) { | 
| pierre@0 | 818         if ($node->status != 1 && $node->adstatus == 'active') { | 
| pierre@0 | 819           $node->adstatus = 'unpublished'; | 
| pierre@0 | 820         } | 
| pierre@0 | 821         $activated = $node->adstatus == 'active' ? time() : 0; | 
| pierre@0 | 822         if (!isset($node->autoactive)) { | 
| pierre@0 | 823           $node->autoactivate = 0; | 
| pierre@0 | 824         } | 
| pierre@0 | 825         if (!isset($node->maxviews)) { | 
| pierre@0 | 826           $node->maxviews = 0; | 
| pierre@0 | 827         } | 
| pierre@0 | 828         if (!isset($node->maxclicks)) { | 
| pierre@0 | 829           $node->maxclicks = 0; | 
| pierre@0 | 830         } | 
| pierre@0 | 831         db_query("INSERT INTO {ads} (aid, uid, adstatus, adtype, redirect, autoactivate, autoexpire, activated, maxviews, maxclicks) VALUES(%d, %d, '%s', '%s', '%s', %d, %d, %d, %d, %d)", $node->nid, $node->uid, $node->adstatus, $node->adtype, url('ad/redirect/'. $node->nid, array('absolute' => TRUE)), $node->autoactivate ? strtotime($node->autoactivate) : '', $node->autoexpire ? strtotime($node->autoexpire) : '', $activated, $node->maxviews, $node->maxclicks); | 
| pierre@0 | 832         ad_statistics_increment($node->nid, 'create'); | 
| pierre@0 | 833       } | 
| pierre@0 | 834       break; | 
| pierre@0 | 835 | 
| pierre@0 | 836     case 'update': | 
| pierre@0 | 837       if (isset($node->adtype)) { | 
| pierre@0 | 838         $ad = db_fetch_object(db_query('SELECT * FROM {ads} WHERE aid = %d', $node->nid)); | 
| pierre@0 | 839         // Ad must be in approved state to be able to autoactivate it. | 
| pierre@0 | 840         if ($node->adstatus != 'approved' && $node->autoactivate) { | 
| pierre@0 | 841           if ($node->adstatus == 'active') { | 
| pierre@0 | 842             // This ad is already active, no need to autoactivate it. | 
| pierre@0 | 843             $node->autoactivate = 0; | 
| pierre@0 | 844           } | 
| pierre@0 | 845           else { | 
| pierre@0 | 846             drupal_set_message(t('This ad will not be automatically activated at the scheduled time because it is not in the <em>approved</em> state.'), 'error'); | 
| pierre@0 | 847           } | 
| pierre@0 | 848         } | 
| pierre@0 | 849         // If this node has been upublished, the ad should no longer be active. | 
| pierre@0 | 850         if ($node->status != 1 && $node->adstatus == 'active') { | 
| pierre@0 | 851           $node->adstatus = 'unpublished'; | 
| pierre@0 | 852         } | 
| pierre@0 | 853         // If a previously unpublished node has been published, reactivate the | 
| pierre@0 | 854         // the ad. | 
| pierre@0 | 855         else if ($node->status == 1 && $node->adstatus == 'unpublished') { | 
| pierre@0 | 856           $node->adstatus = 'active'; | 
| pierre@0 | 857           // Special "publish" event, may as well track it even though we'll | 
| pierre@0 | 858           // next also record an "active" event. | 
| pierre@0 | 859           ad_statistics_increment($node->nid, 'publish'); | 
| pierre@0 | 860         } | 
| pierre@0 | 861         // Check if ad is being manually activated. | 
| pierre@0 | 862         if ($ad->adstatus != 'active' && $node->adstatus == 'active') { | 
| pierre@0 | 863           $activated = time(); | 
| pierre@0 | 864         } | 
| pierre@0 | 865         // Check if ad is being manually expired. | 
| pierre@0 | 866         else if ($ad->adstatus != 'expired' && $node->adstatus == 'expired') { | 
| pierre@0 | 867           // Ad has been manually expired. | 
| pierre@0 | 868           $expired = time(); | 
| pierre@0 | 869         } | 
| pierre@0 | 870         // Ad has not been manually activated or expired, preserve timestamps. | 
| pierre@0 | 871         else { | 
| pierre@0 | 872           $activated = $ad->activated; | 
| pierre@0 | 873           $expired = $ad->expired; | 
| pierre@0 | 874         } | 
| pierre@0 | 875         // Ad status has changed, record the event. | 
| pierre@0 | 876         if ($ad->adstatus != $node->adstatus) { | 
| pierre@0 | 877           ad_statistics_increment($node->nid, $node->adstatus); | 
| pierre@0 | 878         } | 
| pierre@0 | 879         // Update ads table with new information. | 
| pierre@0 | 880         db_query("UPDATE {ads} SET uid = %d, adstatus = '%s', adtype = '%s', redirect = '%s', autoactivate = %d, autoexpire = %d, activated = %d, maxviews = %d, maxclicks = %d, expired = %d WHERE aid = %d", $node->uid, $node->adstatus, $node->adtype, url('ad/redirect/'. $node->nid, array('absolute' => TRUE)), isset($node->autoactivate) && $node->autoactivate > 0 ? strtotime($node->autoactivate) : '', isset($node->autoexpire) && $node->autoexpire > 0 ? strtotime($node->autoexpire) : '', $activated, isset($node->maxviews) ? (int)$node->maxviews : 0, isset($node->maxclicks) ? (int)$node->maxclicks : 0, isset($expired) ? $expired : 0, $node->nid); | 
| pierre@0 | 881         ad_statistics_increment($node->nid, 'update'); | 
| pierre@0 | 882       } | 
| pierre@0 | 883       break; | 
| pierre@0 | 884 | 
| pierre@0 | 885     case 'delete': | 
| pierre@0 | 886       db_query("DELETE FROM {ads} WHERE aid = %d", $node->nid); | 
| pierre@0 | 887       db_query("DELETE FROM {ad_statistics} WHERE aid = %d", $node->nid); | 
| pierre@0 | 888       // All that's left of the ad is a single timestamp as to when it was | 
| pierre@0 | 889       // deleted. | 
| pierre@0 | 890       ad_statistics_increment($node->nid, 'delete'); | 
| pierre@0 | 891       break; | 
| pierre@0 | 892 | 
| pierre@0 | 893     case 'view': | 
| pierre@0 | 894       if (isset($node->adtype)) { | 
| pierre@0 | 895         $node = node_prepare($node, $teaser); | 
| pierre@0 | 896         $node->content['body'] = array( | 
| pierre@0 | 897           '#value' => $teaser ? $node->teaser : theme('node_ad', $node, $page), | 
| pierre@0 | 898           '#weight' => 1, | 
| pierre@0 | 899         ); | 
| pierre@0 | 900       } | 
| pierre@0 | 901       break; | 
| pierre@0 | 902   } | 
| pierre@0 | 903   // Allow ad type module to act on nodeapi events.  The adapi hook provides | 
| pierre@0 | 904   // access to additional variables not available in the nodeapi hook. | 
| pierre@0 | 905   if (isset($node->adtype)) { | 
| pierre@0 | 906     // Don't use module_invoke, as in pre-PHP5 the changes to $node won't be | 
| pierre@0 | 907     // passed back. | 
| pierre@0 | 908     $function = "ad_$node->adtype" .'_adapi'; | 
| pierre@0 | 909     if (function_exists($function)) { | 
| pierre@0 | 910       $function($op, $node); | 
| pierre@0 | 911     } | 
| pierre@0 | 912   } | 
| pierre@0 | 913   // Allow ad cache module to act on nodeapi events. | 
| pierre@0 | 914   $cache = variable_get('ad_cache', 'none'); | 
| pierre@0 | 915   if ($cache != 'none') { | 
| pierre@0 | 916     $function = "ad_cache_$cache" .'_adcacheapi'; | 
| pierre@0 | 917     if (function_exists($function)) { | 
| pierre@0 | 918       $function($op, $node); | 
| pierre@0 | 919     } | 
| pierre@0 | 920   } | 
| pierre@0 | 921 } | 
| pierre@0 | 922 | 
| pierre@0 | 923 function ad_adapi($op, $node = NULL) { | 
| pierre@0 | 924   switch ($op) { | 
| pierre@0 | 925     case 'permissions': | 
| pierre@0 | 926       return array('access statistics', 'access click history', 'manage status'); | 
| pierre@0 | 927       break; | 
| pierre@0 | 928   } | 
| pierre@0 | 929 } | 
| pierre@0 | 930 | 
| pierre@0 | 931 /** | 
| pierre@0 | 932  * Implementation of hook_menu(). | 
| pierre@0 | 933  */ | 
| pierre@0 | 934 function ad_menu() { | 
| pierre@0 | 935   $items = array(); | 
| pierre@0 | 936 | 
| pierre@0 | 937   $items['admin/content/ad'] = array( | 
| pierre@0 | 938     'title' => 'Ads', | 
| pierre@0 | 939     'page callback' => 'ad_admin_list', | 
| pierre@0 | 940     'access arguments' => array('administer advertisements'), | 
| pierre@0 | 941     'description' => 'Configure and manage your advertising system.', | 
| pierre@0 | 942     'file' => 'ad.admin.inc', | 
| pierre@0 | 943   ); | 
| pierre@0 | 944   $items['admin/content/ad/list'] = array( | 
| pierre@0 | 945     'title' => 'List', | 
| pierre@0 | 946     'page callback' => 'ad_admin_list', | 
| pierre@0 | 947     'access arguments' => array('administer advertisements'), | 
| pierre@0 | 948     'type' => MENU_DEFAULT_LOCAL_TASK, | 
| pierre@0 | 949     'file' => 'ad.admin.inc', | 
| pierre@0 | 950   ); | 
| pierre@0 | 951   $items['admin/content/ad/statistics'] = array( | 
| pierre@0 | 952     'title' => 'Statistics', | 
| pierre@0 | 953     'page callback' => 'drupal_get_form', | 
| pierre@0 | 954     'page arguments' => array('ad_admin_statistics'), | 
| pierre@0 | 955     'access arguments' => array('administer advertisements'), | 
| pierre@0 | 956     'type' => MENU_LOCAL_TASK, | 
| pierre@0 | 957     'weight' => 1, | 
| pierre@0 | 958     'file' => 'ad.admin.inc', | 
| pierre@0 | 959   ); | 
| pierre@0 | 960   $items['admin/content/ad/configure'] = array( | 
| pierre@0 | 961     'title' => 'Settings', | 
| pierre@0 | 962     'page callback' => 'drupal_get_form', | 
| pierre@0 | 963     'page arguments' => array('ad_admin_configure_settings'), | 
| pierre@0 | 964     'access arguments' => array('administer advertisements'), | 
| pierre@0 | 965     'type' => MENU_LOCAL_TASK, | 
| pierre@0 | 966     'weight' => 3, | 
| pierre@0 | 967     'file' => 'ad.admin.inc', | 
| pierre@0 | 968   ); | 
| pierre@0 | 969 | 
| pierre@0 | 970   ad_menu_add_global_settings($items); | 
| pierre@0 | 971 | 
| pierre@0 | 972   $items['admin/content/ad/groups'] = array( | 
| pierre@0 | 973     'title' => 'Ad groups', | 
| pierre@0 | 974     'page callback' => 'ad_admin_groups_list', | 
| pierre@0 | 975     'access arguments' => array('administer advertisements'), | 
| pierre@0 | 976     'type' => MENU_LOCAL_TASK, | 
| pierre@0 | 977     'weight' => 5, | 
| pierre@0 | 978     'file' => 'ad.admin.inc', | 
| pierre@0 | 979   ); | 
| pierre@0 | 980   $items['admin/content/ad/groups/list'] = array( | 
| pierre@0 | 981     'title' => 'List', | 
| pierre@0 | 982     'page callback' => 'ad_admin_groups_list', | 
| pierre@0 | 983     'access arguments' => array('administer advertisements'), | 
| pierre@0 | 984     'type' => MENU_DEFAULT_LOCAL_TASK, | 
| pierre@0 | 985     'weight' => 0, | 
| pierre@0 | 986     'file' => 'ad.admin.inc', | 
| pierre@0 | 987   ); | 
| pierre@0 | 988   $items['admin/content/ad/groups/add'] = array( | 
| pierre@0 | 989     'title' => 'Create group', | 
| pierre@0 | 990     'page callback' => 'drupal_get_form', | 
| pierre@0 | 991     'page arguments' => array('ad_admin_group_form'), | 
| pierre@0 | 992     'access arguments' => array('administer advertisements'), | 
| pierre@0 | 993     'type' => MENU_LOCAL_TASK, | 
| pierre@0 | 994     'weight' => 3, | 
| pierre@0 | 995     'file' => 'ad.admin.inc', | 
| pierre@0 | 996   ); | 
| pierre@0 | 997   $items["admin/content/ad/groups/%ad_group/edit"] = array( | 
| pierre@0 | 998     'title' => 'Edit group', | 
| pierre@0 | 999     'page callback' => 'drupal_get_form', | 
| pierre@0 | 1000     'page arguments' => array('ad_admin_group_form', 4), | 
| pierre@0 | 1001     'access arguments' => array('administer advertisements'), | 
| pierre@0 | 1002     'weight' => 1, | 
| pierre@0 | 1003     'file' => 'ad.admin.inc', | 
| pierre@0 | 1004   ); | 
| pierre@0 | 1005   $items["admin/content/ad/groups/%ad_group/delete"] = array( | 
| pierre@0 | 1006     'title' => 'Delete group', | 
| pierre@0 | 1007     'page callback' => 'drupal_get_form', | 
| pierre@0 | 1008     'page arguments' => array('ad_confirm_group_delete', 4), | 
| pierre@0 | 1009     'access arguments' => array('administer advertisements'), | 
| pierre@0 | 1010     'weight' => 2, | 
| pierre@0 | 1011     'file' => 'ad.admin.inc', | 
| pierre@0 | 1012   ); | 
| pierre@0 | 1013   $items['admin/content/ad/configure/global'] = array( | 
| pierre@0 | 1014     'title' => 'Global settings', | 
| pierre@0 | 1015     'page callback' => 'drupal_get_form', | 
| pierre@0 | 1016     'page arguments' => array('ad_admin_configure_settings'), | 
| pierre@0 | 1017     'access arguments' => array('administer advertisements'), | 
| pierre@0 | 1018     'type' => MENU_DEFAULT_LOCAL_TASK, | 
| pierre@0 | 1019     'weight' => 0, | 
| pierre@0 | 1020     'file' => 'ad.admin.inc', | 
| pierre@0 | 1021   ); | 
| pierre@0 | 1022   $items["node/%node/details/%"] = array( | 
| pierre@0 | 1023     'title' => 'Click details', | 
| pierre@0 | 1024     'page callback' => 'ad_click_details', | 
| pierre@0 | 1025     'page arguments' => array(1, 3), | 
| pierre@0 | 1026     'access arguments' => array(1, 'access click history'), | 
| pierre@0 | 1027     'access callback' => 'ad_adaccess', | 
| pierre@0 | 1028     'type' => MENU_CALLBACK, | 
| pierre@0 | 1029     'file' => 'ad.pages.inc', | 
| pierre@0 | 1030   ); | 
| pierre@0 | 1031   $items["ad/redirect/%/%/%"] = array( | 
| pierre@0 | 1032     'access arguments' => array('show advertisements'), | 
| pierre@0 | 1033     'type' => MENU_CALLBACK, | 
| pierre@0 | 1034     'page callback' => 'ad_redirect', | 
| pierre@0 | 1035     'page arguments' => (array(2, 3, 4)), | 
| pierre@0 | 1036   ); | 
| pierre@0 | 1037   $items["ad/redirect/%/%"] = array( | 
| pierre@0 | 1038     'access arguments' => array('show advertisements'), | 
| pierre@0 | 1039     'type' => MENU_CALLBACK, | 
| pierre@0 | 1040     'page callback' => 'ad_redirect', | 
| pierre@0 | 1041     'page arguments' => (array(2, 3)), | 
| pierre@0 | 1042   ); | 
| pierre@0 | 1043 | 
| pierre@0 | 1044   return $items; | 
| pierre@0 | 1045 } | 
| pierre@0 | 1046 | 
| pierre@0 | 1047 /** | 
| pierre@0 | 1048  * Load settings for all ad modules. Those modules, who don't | 
| pierre@0 | 1049  * have their settings form, will get a standard one. | 
| pierre@0 | 1050  */ | 
| pierre@0 | 1051 function ad_menu_add_global_settings(&$menu_items) { | 
| pierre@0 | 1052   $adtypes = ad_get_types(); | 
| pierre@0 | 1053   foreach ($adtypes as $type => $name) { | 
| pierre@0 | 1054     // Ad type global settings. | 
| pierre@0 | 1055     $settings = 'ad_'. $type .'_global_settings'; | 
| pierre@0 | 1056     if (!function_exists($settings)) { | 
| pierre@0 | 1057       $settings = 'ad_no_global_settings'; | 
| pierre@0 | 1058     } | 
| pierre@0 | 1059     $menu_items['admin/content/ad/configure/'. $type] = array( | 
| pierre@0 | 1060       'title' => $name, | 
| pierre@0 | 1061       'page callback' => 'drupal_get_form', | 
| pierre@0 | 1062       'page arguments' => array($settings), | 
| pierre@0 | 1063       'access arguments' => array('administer advertisements'), | 
| pierre@0 | 1064       'type' => MENU_LOCAL_TASK, | 
| pierre@0 | 1065       'weight' => 2, | 
| pierre@0 | 1066       'file' => 'ad.admin.inc', | 
| pierre@0 | 1067     ); | 
| pierre@0 | 1068   } | 
| pierre@0 | 1069 } | 
| pierre@0 | 1070 | 
| pierre@0 | 1071 /** | 
| pierre@0 | 1072  * Drupal menu wildcard Ad group loader | 
| pierre@0 | 1073  */ | 
| pierre@0 | 1074 function ad_group_load($tid) { | 
| pierre@0 | 1075   if (!is_numeric($tid)) { | 
| pierre@0 | 1076     return FALSE; | 
| pierre@0 | 1077   } | 
| pierre@0 | 1078   $group = ad_groups_list(TRUE, $tid); | 
| pierre@0 | 1079   if (!isset($group)) { | 
| pierre@0 | 1080     return FALSE; | 
| pierre@0 | 1081   } | 
| pierre@0 | 1082   return $group; | 
| pierre@0 | 1083 } | 
| pierre@0 | 1084 | 
| pierre@0 | 1085 /** | 
| pierre@0 | 1086  * Implementation of hook_block(). | 
| pierre@0 | 1087  */ | 
| pierre@0 | 1088 function ad_block($op = 'list', $delta = 0, $edit = array()) { | 
| pierre@0 | 1089   switch ($op) { | 
| pierre@0 | 1090     case 'list': | 
| pierre@0 | 1091       $blocks = array(); | 
| pierre@0 | 1092       $groups = ad_groups_list(); | 
| pierre@0 | 1093       foreach ($groups as $tid => $name) { | 
| pierre@0 | 1094         $blocks[$tid]['info'] = t('ad group: @name', array('@name' => $name)); | 
| pierre@0 | 1095       } | 
| pierre@0 | 1096       return $blocks; | 
| pierre@0 | 1097     case 'configure': | 
| pierre@0 | 1098       $form['ad_block_quantity_'. $delta] = array( | 
| pierre@0 | 1099         '#type' => 'select', | 
| pierre@0 | 1100         '#title' => t('Number of ads'), | 
| pierre@0 | 1101         '#default_value' => variable_get('ad_block_quantity_'. $delta, 1), | 
| pierre@0 | 1102         '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25)), | 
| pierre@0 | 1103         '#description' => t('Select the maximum number of unique ads that should be displayed together in this block.  If you specify a number larger than the maximum number of ads in this ad group, all ads will be displayed once.'), | 
| pierre@0 | 1104       ); | 
| pierre@0 | 1105       return $form; | 
| pierre@0 | 1106     case 'save': | 
| pierre@0 | 1107       variable_set('ad_block_quantity_'. $delta, $edit['ad_block_quantity_'. $delta]); | 
| pierre@0 | 1108       break; | 
| pierre@0 | 1109     case 'view': | 
| pierre@0 | 1110       $groups = ad_groups_list(); | 
| pierre@0 | 1111       $block['content'] = ad($delta, variable_get('ad_block_quantity_'. $delta, 1)); | 
| pierre@0 | 1112       return $block; | 
| pierre@0 | 1113   } | 
| pierre@0 | 1114 } | 
| pierre@0 | 1115 | 
| pierre@0 | 1116 /** | 
| pierre@0 | 1117  * Determine whether the user has a given privilege. | 
| pierre@0 | 1118  * | 
| pierre@0 | 1119  * @param $ad | 
| pierre@0 | 1120  *   Node object or aid of advertisement. | 
| pierre@0 | 1121  * @param $permission | 
| pierre@0 | 1122  *   Special Ad owners permission which should be checked (such as 'manage owners') | 
| pierre@0 | 1123  * @param $account | 
| pierre@0 | 1124  *   User object, which are accessing the ad or current user by default. | 
| pierre@0 | 1125  */ | 
| pierre@0 | 1126 function ad_adaccess($ad, $permission, $account = NULL) { | 
| pierre@0 | 1127   global $user; | 
| pierre@0 | 1128   static $permissions = array(); | 
| pierre@0 | 1129 | 
| pierre@0 | 1130   if (!isset($account)) { | 
| pierre@0 | 1131     $account = $user; | 
| pierre@0 | 1132   } | 
| pierre@0 | 1133 | 
| pierre@0 | 1134   // User #1 has all privileges: | 
| pierre@0 | 1135   if ($account->uid == 1) { | 
| pierre@0 | 1136     return TRUE; | 
| pierre@0 | 1137   } | 
| pierre@0 | 1138 | 
| pierre@0 | 1139   // If you have administer permissions, you have all permissions. | 
| pierre@0 | 1140   if (user_access('administer advertisements', $account)) { | 
| pierre@0 | 1141     return TRUE; | 
| pierre@0 | 1142   } | 
| pierre@0 | 1143 | 
| pierre@0 | 1144   // Handle ad owners access | 
| pierre@0 | 1145   if (module_exists('ad_owners')) { | 
| pierre@0 | 1146     return ad_owners_adaccess($ad, $permission, $account); | 
| pierre@0 | 1147   } | 
| pierre@0 | 1148 | 
| pierre@0 | 1149   return FALSE; | 
| pierre@0 | 1150 } | 
| pierre@0 | 1151 | 
| pierre@0 | 1152 /** | 
| pierre@0 | 1153  * Returns ad types data. | 
| pierre@0 | 1154  * | 
| pierre@0 | 1155  * @param $op | 
| pierre@0 | 1156  *  If set to 'name', will only return array of type names ($type => $name). | 
| pierre@0 | 1157  *  If set to 'data', will return all of the type's data | 
| pierre@0 | 1158  * @param $type | 
| pierre@0 | 1159  *  If not specified, will return array of all available types, else will | 
| pierre@0 | 1160  *  return specific type's name or data. | 
| pierre@0 | 1161  */ | 
| pierre@0 | 1162 function ad_get_types($op = 'name', $type = NULL) { | 
| pierre@0 | 1163   $adtypes = module_invoke_all('adapi', 'type', array()); | 
| pierre@0 | 1164   switch ($op) { | 
| pierre@0 | 1165     case 'name': | 
| pierre@0 | 1166       if (isset($type)) { | 
| pierre@0 | 1167         return $adtypes[$type]['name']; | 
| pierre@0 | 1168       } | 
| pierre@0 | 1169       else { | 
| pierre@0 | 1170         foreach ($adtypes as $type => $data) { | 
| pierre@0 | 1171           $adtypes[$type] = $data['name']; | 
| pierre@0 | 1172         } | 
| pierre@0 | 1173         return $adtypes; | 
| pierre@0 | 1174       } | 
| pierre@0 | 1175     case 'data': | 
| pierre@0 | 1176       if (isset($type)) { | 
| pierre@0 | 1177         return $adtypes[$type]; | 
| pierre@0 | 1178       } | 
| pierre@0 | 1179       else { | 
| pierre@0 | 1180         return $adtypes; | 
| pierre@0 | 1181       } | 
| pierre@0 | 1182   } | 
| pierre@0 | 1183 } | 
| pierre@0 | 1184 | 
| pierre@0 | 1185 /** | 
| pierre@0 | 1186  * Return an array of all groups, or a specific group. | 
| pierre@0 | 1187  * | 
| pierre@0 | 1188  * @param $object | 
| pierre@0 | 1189  *  If FALSE, will return only name of group(s).  If TRUE, will return full | 
| pierre@0 | 1190  *  group object including ->name, ->description, and ->tid. | 
| pierre@0 | 1191  * @param $tid | 
| pierre@0 | 1192  *  If set to an integer >0, will only return group info about that specific | 
| pierre@0 | 1193  *  group. | 
| pierre@0 | 1194  */ | 
| pierre@0 | 1195 function ad_groups_list($object = FALSE, $tid = NULL) { | 
| pierre@0 | 1196   static $groups = array(); | 
| pierre@0 | 1197   static $names = array(); | 
| pierre@0 | 1198 | 
| pierre@0 | 1199   // Return the full group object(s). | 
| pierre@0 | 1200   if ($object) { | 
| pierre@0 | 1201     if (empty($groups)) { | 
| pierre@0 | 1202       $tids = taxonomy_get_tree(_ad_get_vid()); | 
| pierre@0 | 1203       if (is_array($tids)) { | 
| pierre@0 | 1204         foreach ($tids as $group) { | 
| pierre@0 | 1205           $groups[$group->tid]->name = $group->name; | 
| pierre@0 | 1206           $groups[$group->tid]->description = $group->description; | 
| pierre@0 | 1207           $groups[$group->tid]->tid = $group->tid; | 
| pierre@0 | 1208           $groups[$group->tid]->weight = $group->weight; | 
| pierre@0 | 1209         } | 
| pierre@0 | 1210       } | 
| pierre@0 | 1211       // Hard coded "default" group with tid of 0. | 
| pierre@0 | 1212       $groups[0]->name = t('default'); | 
| pierre@0 | 1213       $groups[0]->description = t('The default ad group is comprised of all ads not assigned to any other ad group.'); | 
| pierre@0 | 1214       $groups[0]->tid = 0; | 
| pierre@0 | 1215       $groups[0]->weight = 0; | 
| pierre@0 | 1216     } | 
| pierre@0 | 1217     // Return a specific group object. | 
| pierre@0 | 1218     if ((int)$tid) { | 
| pierre@0 | 1219       return $groups[$tid]; | 
| pierre@0 | 1220     } | 
| pierre@0 | 1221     // Return an array of all group objects. | 
| pierre@0 | 1222     else { | 
| pierre@0 | 1223       return $groups; | 
| pierre@0 | 1224     } | 
| pierre@0 | 1225   } | 
| pierre@0 | 1226   // Return only the group name(s). | 
| pierre@0 | 1227   else { | 
| pierre@0 | 1228     if (empty($names)) { | 
| pierre@0 | 1229       $tids = taxonomy_get_tree(_ad_get_vid()); | 
| pierre@0 | 1230       if (is_array($tids)) { | 
| pierre@0 | 1231         foreach ($tids as $group) { | 
| pierre@0 | 1232           $names[$group->tid] = $group->name; | 
| pierre@0 | 1233         } | 
| pierre@0 | 1234       } | 
| pierre@0 | 1235       // Hard coded "default" group with tid of 0. | 
| pierre@0 | 1236       $names[0] = t('default'); | 
| pierre@0 | 1237     } | 
| pierre@0 | 1238     // Return a specific group name. | 
| pierre@0 | 1239     if ((int)$tid) { | 
| pierre@0 | 1240       return $names[$tid]; | 
| pierre@0 | 1241     } | 
| pierre@0 | 1242     // Return an array of all group names. | 
| pierre@0 | 1243     else { | 
| pierre@0 | 1244       return $names; | 
| pierre@0 | 1245     } | 
| pierre@0 | 1246   } | 
| pierre@0 | 1247 } | 
| pierre@0 | 1248 | 
| pierre@0 | 1249 /** | 
| pierre@0 | 1250  * Implement ad notify api _hook. | 
| pierre@0 | 1251  */ | 
| pierre@0 | 1252 function ad_adnotifyapi($op, $arg1 = NULL, $arg2 = NULL) { | 
| pierre@0 | 1253   switch ($op) { | 
| pierre@0 | 1254     // Make the following events available for notification. | 
| pierre@0 | 1255     case 'register': | 
| pierre@0 | 1256       return array( | 
| pierre@0 | 1257         '-expired' => t('Email @when before the advertisement will expire.'), | 
| pierre@0 | 1258         'expired' => t('Email @when after the advertisement is expired.'), | 
| pierre@0 | 1259         '-active' => t('Email @when before the advertisement will be activated (if scheduled).'), | 
| pierre@0 | 1260         'active' => t('Email @when after the advertisement is activated.'), | 
| pierre@0 | 1261         'click' => t('Email @when after the advertisement is clicked.'), | 
| pierre@0 | 1262         'approved' => t('Email @when after the advertisement is approved.'), | 
| pierre@0 | 1263         'denied' => t('Email @when after the advertisement is denied.'), | 
| pierre@0 | 1264       ); | 
| pierre@0 | 1265       break; | 
| pierre@0 | 1266     case '-expired': | 
| pierre@0 | 1267       $node = node_load($arg1->aid); | 
| pierre@0 | 1268       if (isset($node->autoexpire) && $node->autoexpire) { | 
| pierre@0 | 1269         if ((time() + $arg1->delay >= $node->autoexpire) && | 
| pierre@0 | 1270             ($arg1->sent + $arg1->delay < $node->autoexpire)) { | 
| pierre@0 | 1271           return array('-expired' => 1); | 
| pierre@0 | 1272         } | 
| pierre@0 | 1273       } | 
| pierre@0 | 1274       break; | 
| pierre@0 | 1275     case '-active': | 
| pierre@0 | 1276       $node = node_load($arg1->aid); | 
| pierre@0 | 1277       if (isset($node->autoactivate) && $node->autoactivate) { | 
| pierre@0 | 1278         if ((time() + $arg1->delay >= $node->autoactivate) && | 
| pierre@0 | 1279             ($arg1->sent + $arg1->delay < $node->autoactivate)) { | 
| pierre@0 | 1280           return array('-active' => 1); | 
| pierre@0 | 1281         } | 
| pierre@0 | 1282       } | 
| pierre@0 | 1283       break; | 
| pierre@0 | 1284     case 'mail_text': | 
| pierre@0 | 1285       switch ($arg1) { | 
| pierre@0 | 1286         case 'expired': | 
| pierre@0 | 1287           return array( | 
| pierre@0 | 1288             'subject' => t('[%sitename ad] %event notification'), | 
| pierre@0 | 1289             'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" that was being displayed on the %sitename website has expired.\n\n  Your advertisement was viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n  You can view additional statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"), | 
| pierre@0 | 1290           ); | 
| pierre@0 | 1291         case '-expired': | 
| pierre@0 | 1292           return array( | 
| pierre@0 | 1293             'subject' => t('[%sitename ad] expiration notification'), | 
| pierre@0 | 1294             'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" that is being displayed on the %sitename website will expire on %autoexpire_large.\n\n  Your advertisement has been viewed %today_views times and clicked %today_clicks times today.  It was viewed %yesterday_views times and clicked %yesterday_clicks times yesterday.  It has been viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n  You can view additional statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"), | 
| pierre@0 | 1295           ); | 
| pierre@0 | 1296         case 'active': | 
| pierre@0 | 1297           return array( | 
| pierre@0 | 1298             'subject' => t('[%sitename ad] %event notification'), | 
| pierre@0 | 1299             'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" is now actively being displayed on the %sitename website.\n\n  Your advertisement has been viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n  You can view additional statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"), | 
| pierre@0 | 1300           ); | 
| pierre@0 | 1301         case '-active': | 
| pierre@0 | 1302           return array( | 
| pierre@0 | 1303             'subject' => t('[%sitename ad] activation notification'), | 
| pierre@0 | 1304             'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" will be actively displayed on the %sitename website on %autoactivate_large.\n\n  You can view statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"), | 
| pierre@0 | 1305           ); | 
| pierre@0 | 1306         case 'click': | 
| pierre@0 | 1307           return array( | 
| pierre@0 | 1308             'subject' => t('[%sitename ad] %event notification'), | 
| pierre@0 | 1309             'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" on the %sitename website has been clicked.\n\n  Your advertisement has been viewed %today_views times and clicked %today_clicks times today.  It was viewed %yesterday_views times and clicked %yesterday_clicks times yesterday.  It has been viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n  You will receive this %frequency  You can view additional statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"), | 
| pierre@0 | 1310           ); | 
| pierre@0 | 1311         case 'approved': | 
| pierre@0 | 1312           return array( | 
| pierre@0 | 1313             'subject' => t('[%sitename ad] %event notification'), | 
| pierre@0 | 1314             'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" on the %sitename website has been approved.\n\n  You can view statistics about this advertisement at the following url:\n    %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"), | 
| pierre@0 | 1315           ); | 
| pierre@0 | 1316         case 'denied': | 
| pierre@0 | 1317           return array( | 
| pierre@0 | 1318             'subject' => t('[%sitename ad] %event notification'), | 
| pierre@0 | 1319             'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" on the %sitename website has been denied and will not be displayed.\n\n  You can view statistics about this advertisement at the following url:\n    %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"), | 
| pierre@0 | 1320           ); | 
| pierre@0 | 1321       } | 
| pierre@0 | 1322       break; | 
| pierre@0 | 1323   } | 
| pierre@0 | 1324 } | 
| pierre@0 | 1325 | 
| pierre@0 | 1326 function _ad_check_installation() { | 
| pierre@0 | 1327   // Verify serve.php exists and is readable. | 
| pierre@0 | 1328   $adserve = variable_get('adserve', ''); | 
| pierre@0 | 1329   $adserveinc = variable_get('adserveinc', ''); | 
| pierre@0 | 1330   if (!file_exists($adserve)) { | 
| pierre@0 | 1331     // The serve.php file should be in the same directory as the ad.module. | 
| pierre@0 | 1332     $adserve = drupal_get_path('module', 'ad') .'/serve.php'; | 
| pierre@0 | 1333     variable_set('adserve', $adserve); | 
| pierre@0 | 1334   } | 
| pierre@0 | 1335   if (!is_readable($adserve)) { | 
| pierre@0 | 1336     variable_set('adserve', ''); | 
| pierre@0 | 1337     drupal_set_message(t('Failed to read the required file %filename.  Please make the file readable by the webserver process.  No ads can be displayed until this problem is resolved.', array('%filename' => $adserve)), 'error'); | 
| pierre@0 | 1338   } | 
| pierre@0 | 1339   if (!file_exists($adserveinc)) { | 
| pierre@0 | 1340     // The adserve.inc file should be in the same directory as the ad.module. | 
| pierre@0 | 1341     $adserveinc = drupal_get_path('module', 'ad') .'/adserve.inc'; | 
| pierre@0 | 1342     variable_set('adserveinc', $adserveinc); | 
| pierre@0 | 1343   } | 
| pierre@0 | 1344   if (!is_readable($adserveinc)) { | 
| pierre@0 | 1345     variable_set('adserveinc', ''); | 
| pierre@0 | 1346     drupal_set_message(t('Failed to read the required file %filename.  Please make the file readable by the webserver process.  No ads can be displayed until this problem is resolved.', array('%filename' => $adserveinc)), 'error'); | 
| pierre@0 | 1347   } | 
| pierre@0 | 1348 | 
| pierre@0 | 1349   // Validate vid in vocabulary table. | 
| pierre@0 | 1350   $vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE module = 'ad'")); | 
| pierre@0 | 1351   if ($vid != variable_get('ad_group_vid', '')) { | 
| pierre@0 | 1352     drupal_set_message(t('Invalid vocabulary defined for advertisements, attempting to auto-fix.'), 'error'); | 
| pierre@0 | 1353     if ($vid) { | 
| pierre@0 | 1354       db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d OR type = 'ad'", variable_get('ad_group_vid', '')); | 
| pierre@0 | 1355       variable_set('ad_group_vid_restore', variable_get('ad_group_vid', '')); | 
| pierre@0 | 1356     } | 
| pierre@0 | 1357     variable_del('ad_group_vid'); | 
| pierre@0 | 1358   } | 
| pierre@0 | 1359   else { | 
| pierre@0 | 1360     // Validate vid in vocabulary_node_types table. | 
| pierre@0 | 1361     $result = db_query("SELECT vid FROM {vocabulary_node_types} WHERE type = 'ad'"); | 
| pierre@0 | 1362     $found = FALSE; | 
| pierre@0 | 1363     while ($vocab = db_fetch_object($result)) { | 
| pierre@0 | 1364       if ($vocab->vid == variable_get('ad_group_vid', '')) { | 
| pierre@0 | 1365         $found = TRUE; | 
| pierre@0 | 1366       } | 
| pierre@0 | 1367     } | 
| pierre@0 | 1368     if (!$found) { | 
| pierre@0 | 1369       drupal_set_message(t('Missing vocabulary node type for advertisements, attempting to auto-fix.'), 'error'); | 
| pierre@0 | 1370       db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d OR type = 'ad'", variable_get('ad_group_vid', '')); | 
| pierre@0 | 1371       db_query("DELETE FROM {vocabulary} WHERE vid = %d", variable_get('ad_group_vid', '')); | 
| pierre@0 | 1372       variable_set('ad_group_vid_restore', variable_get('ad_group_vid', '')); | 
| pierre@0 | 1373       variable_del('ad_group_vid'); | 
| pierre@0 | 1374     } | 
| pierre@0 | 1375   } | 
| pierre@0 | 1376 | 
| pierre@0 | 1377   _ad_get_vid(); | 
| pierre@0 | 1378   // Preserve old ad groups, if any. | 
| pierre@0 | 1379   if (($old = variable_get('ad_group_vid_restore', '')) && | 
| pierre@0 | 1380        $vid = variable_get('ad_group_vid', '')) { | 
| pierre@0 | 1381     drupal_set_message(t('Restoring orphaned ad group configuration.')); | 
| pierre@0 | 1382     db_query('UPDATE {term_data} SET vid = %d WHERE vid = %d', $vid, $old); | 
| pierre@0 | 1383     variable_set('ad_group_vid_restore', ''); | 
| pierre@0 | 1384   } | 
| pierre@0 | 1385 | 
| pierre@0 | 1386   $rid = db_result(db_query_range("SELECT rid FROM {permission} WHERE perm LIKE '%%show advertisements%%'", 1)); | 
| pierre@0 | 1387   if (!$rid) { | 
| pierre@0 | 1388     drupal_set_message(t('Be sure to enable "!show" permissions for all roles that you wish to see advertisements.', array('!show' => l(t('show advertisements'), 'admin/user/permissions')))); | 
| pierre@0 | 1389   } | 
| pierre@0 | 1390 | 
| pierre@0 | 1391   // Allow modules to define an action to take each time an ad is served. | 
| pierre@0 | 1392   // When modules define 'adserve_select' or 'adserve_filter', they must set | 
| pierre@0 | 1393   // the 'function' and 'path' parameters.  The 'weight' parameter can | 
| pierre@0 | 1394   // optionally be set. | 
| pierre@0 | 1395   //  function: the function to call when serving an add | 
| pierre@0 | 1396   //  path: the path to the include file where $function is defined | 
| pierre@0 | 1397   // Modules can define actions that happen when advertisements are served. | 
| pierre@0 | 1398   // Currently support actions are: | 
| pierre@0 | 1399   //  - init_text   (display content before displaying ads) // TODO | 
| pierre@0 | 1400   //  - select      (alter which ads are selected to be displayed) // TODO | 
| pierre@0 | 1401   //  - filter      (filter selected ads before they are displayed) // TODO | 
| pierre@0 | 1402   //  - exit_text   (display content after displaying ads) // TODO | 
| pierre@0 | 1403   $hooks = array('init_text', 'select', 'filter', 'exit_text'); | 
| pierre@0 | 1404   foreach ($hooks as $hook) { | 
| pierre@0 | 1405     $adserve_actions = module_invoke_all('adapi', "adserve_$hook", array()); | 
| pierre@0 | 1406     $actions = array(); | 
| pierre@0 | 1407     foreach ($adserve_actions as $name => $action) { | 
| pierre@0 | 1408       if (is_numeric($action['weight'])) { | 
| pierre@0 | 1409         $weight = $action['weight']; | 
| pierre@0 | 1410       } | 
| pierre@0 | 1411       else { | 
| pierre@0 | 1412         // weight is an optional, defaults to 0 | 
| pierre@0 | 1413         $weight = $action['weight'] = 0; | 
| pierre@0 | 1414       } | 
| pierre@0 | 1415       $actions[$weight .'.'. $name] = $action; | 
| pierre@0 | 1416       $actions[$weight .'.'. $name]['name'] = $name; | 
| pierre@0 | 1417     } | 
| pierre@0 | 1418     // order actions by weight (multiple same-weight actions sorted by alpha) | 
| pierre@0 | 1419     ksort($actions); | 
| pierre@0 | 1420     variable_set("adserve_$hook", serialize($actions)); | 
| pierre@0 | 1421   } | 
| pierre@0 | 1422 | 
| pierre@0 | 1423   module_invoke_all('adapi', 'check_install', array()); | 
| pierre@0 | 1424 } | 
| pierre@0 | 1425 | 
| pierre@0 | 1426 /** | 
| pierre@0 | 1427  * Creates a vocabulary for use by ad groups if not already created. | 
| pierre@0 | 1428  */ | 
| pierre@0 | 1429 function _ad_get_vid() { | 
| pierre@0 | 1430   $vid = variable_get('ad_group_vid', ''); | 
| pierre@0 | 1431   if (empty($vid)) { | 
| pierre@0 | 1432     // No vid stored in the variables table, check if one even exists. | 
| pierre@0 | 1433     $vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE module = '%s'", 'ad')); | 
| pierre@0 | 1434     if (!$vid) { | 
| pierre@0 | 1435       // No vid, so we create one. | 
| pierre@0 | 1436       $edit = array( | 
| pierre@0 | 1437         'name' => t('Ad groups'), | 
| pierre@0 | 1438         'multiple' => 1, | 
| pierre@0 | 1439         'required' => 0, | 
| pierre@0 | 1440         'hierarchy' => 0, | 
| pierre@0 | 1441         'relations' => 0, | 
| pierre@0 | 1442         'module' => 'ad', | 
| pierre@0 | 1443         'nodes' => array('ad' => 1) | 
| pierre@0 | 1444       ); | 
| pierre@0 | 1445 | 
| pierre@0 | 1446       taxonomy_save_vocabulary($edit); | 
| pierre@0 | 1447       $vid = $edit['vid']; | 
| pierre@0 | 1448     } | 
| pierre@0 | 1449     // Save the vid for next time. | 
| pierre@0 | 1450     variable_set('ad_group_vid', $vid); | 
| pierre@0 | 1451   } | 
| pierre@0 | 1452   return $vid; | 
| pierre@0 | 1453 } | 
| pierre@0 | 1454 | 
| pierre@0 | 1455 /** | 
| pierre@0 | 1456  * Builds the necessary HTML to display an image-based impressions counter. | 
| pierre@0 | 1457  */ | 
| pierre@0 | 1458 function ad_display_image($ad, $css = TRUE) { | 
| pierre@0 | 1459   global $base_url; | 
| pierre@0 | 1460   $adserve = variable_get('adserve', ''); | 
| pierre@0 | 1461   $cache = variable_get('ad_cache', 'none'); | 
| pierre@0 | 1462   $variables = "?o=image"; | 
| pierre@0 | 1463   if (is_object($ad)) { | 
| pierre@0 | 1464     $aid = $ad->aid; | 
| pierre@0 | 1465   } | 
| pierre@0 | 1466   else { | 
| pierre@0 | 1467     /** | 
| pierre@0 | 1468      * No ad is specified, so we're just tracking traffic. | 
| pierre@0 | 1469      */ | 
| pierre@0 | 1470     $aid = 0; | 
| pierre@0 | 1471   } | 
| pierre@0 | 1472   $variables .= "&a=$aid"; | 
| pierre@0 | 1473   if ($cache != 'none') { | 
| pierre@0 | 1474     $variables .= '&c='. $cache . module_invoke('ad_cache_'. $cache, 'adcacheapi', 'display_variables', array()); | 
| pierre@0 | 1475   } | 
| pierre@0 | 1476   $output = '<img src="'. url($base_url .'/'. $adserve . $variables) .'" height="0" width="0" alt="view counter" />'; | 
| pierre@0 | 1477   if ($css) { | 
| pierre@0 | 1478     return '<div class="ad-image-counter">'. $output .'</div>'; | 
| pierre@0 | 1479   } | 
| pierre@0 | 1480   else { | 
| pierre@0 | 1481     return $output; | 
| pierre@0 | 1482   } | 
| pierre@0 | 1483 } | 
| pierre@0 | 1484 | 
| pierre@0 | 1485 /** | 
| pierre@0 | 1486  * Retrieve the group name from the nid. | 
| pierre@0 | 1487  */ | 
| pierre@0 | 1488 function _ad_get_group($nid) { | 
| pierre@0 | 1489   static $groups = array(); | 
| pierre@0 | 1490 | 
| pierre@0 | 1491   if (!isset($groups[$nid])) { | 
| pierre@0 | 1492     $result = db_query('SELECT d.name FROM {term_data} d LEFT JOIN {term_node} n ON d.tid = n.tid WHERE n.nid = %d AND d.vid = %d', $nid, _ad_get_vid()); | 
| pierre@0 | 1493     while ($term = db_fetch_object($result)) { | 
| pierre@0 | 1494       $terms[] = $term->name; | 
| pierre@0 | 1495     } | 
| pierre@0 | 1496     if (!empty($terms)) { | 
| pierre@0 | 1497       $groups[$nid] = implode(', ', $terms); | 
| pierre@0 | 1498     } | 
| pierre@0 | 1499     else { | 
| pierre@0 | 1500       $groups[$nid] = t('default'); | 
| pierre@0 | 1501     } | 
| pierre@0 | 1502   } | 
| pierre@0 | 1503 | 
| pierre@0 | 1504   return $groups[$nid]; | 
| pierre@0 | 1505 } | 
| pierre@0 | 1506 |