Link to home
Start Free TrialLog in
Avatar of mysmp
mysmp

asked on

Cannot get Javascript code to display in Internet Explorer, works fine in firefox

Hi, I have an issue with displaying JavaScript code in drupal within a node.  Basically, I am inserting a JavaScript advertisement into the node by left aligning it to the text.  For some reason, it works fine in Firefox, but refuses to even show up in IE.  Please help, I have been trying to fix this for months now.  

FYI....I have been using the "Ad" module in drupal to insert the code.  I am not stuck to this module if you believe it is not appropriate.  The reason I need to insert a javascript code is to geo-target the users using Google Ad Manager.

You can see an example of the image ad that we are currently using, here:  http://www.mysmp.com/day-trading/trading-multiple-time-frames.html

The "free instant analysis" ad is where we want to insert this javascript ad.  

I think the way I coded it is structurally sound but there may be an issue in the style sheet?  If you need me to send any of my drupal files to you, please let me know
Avatar of gwkg
gwkg
Flag of United States of America image

If you have Microsoft Office, it has a javascript debugging tool
http://www.jonathanboutelle.com/mt/archives/2006/01/howto_debug_jav.html
Otherwise try the Javascript console in Opera browser (Opera.com)
Avatar of mysmp
mysmp

ASKER

I am copying and pasting the javascript provided to me by google admanager....I cant really change that.  
No, but you can see what the error is.
Avatar of mysmp

ASKER

k, ill try that....do you think it could be an issue with my style sheet?  Or are you pretty sure its something in the way that IE views the javascript?
Are you thinking that maybe the parent container (<div>,<p>,etc) is hiding the ad?
Do you have a link to the page so I can look at the code?
Avatar of mysmp

ASKER

Hi thanks for the reply:

http://www.mysmp.com/bonds/federal-reserve-bank.html

check this page out if you can...the ad is showing in firefox...but not in IE
Avatar of mysmp

ASKER

And sorry to miss your question...but yes...that was what I was thinking.  Something in the actual stylesheet could be overriding the ad I am putting in?  I could send you the stylesheet if you think that would help
I'm seeing the same content in both IE and Firefox.  What, exactly, aren't you seeing in IE?
The only difference Im seeing is the text not flowing around the "Free Instant Analysis" advertisement.
I'm on my way to a photoshoot, but I'll check your question tomorrow.
Avatar of mysmp

ASKER

Ill attach a screen capture...basically, I do not see the ad appearing in IE at all.  Thank you again for your hard work and time that you spent on this.
firefox-output.png
IE-output.png
Sorry for the delay, I never made it back to the office this weekend.
Which version of you IE are you using?
Here is my screen capture of your page in IE
 
 

1-26-2009-11-23-43-AM.png
Avatar of mysmp

ASKER

Yea, I had to switch the code back so I wouldnt lose too much affiliate commissions.  I have now changed it back to the javascript code for your review....still not working in IE but fine in Firefox....
I still see it, just not with the text flowing around it, like in Mozilla.
What did you switch the code back to in order to see it on your side?
Is this the line of code you are including in your "Ad" module?
<script type="text/javascript" src="http://www.mysmp.com/modules/ad/serve.php?q=1&t=52,0"></script>  

1-26-2009-12-04-27-PM.png
You have a ton of style sheets... where are the styles for this div?
<div class="advertisement" id="group-tids-520">
 
Avatar of mysmp

ASKER

Hi,
Strange that you are seeing it like that.  I don't even see it in IE at all.  I am using IE 7
For me to see it, I had to insert the straight HTML code that the affiliate provides.  

The javascript is from google admanager and the HTML code was uploaded there along with another ad so I could GEOTarget.  

You are correct, I used the AD module in Drupal to accomplish this..  

That code you presented above is not the code that I put into the Ad Module.  This is what is currently in that module:
<div style = float:left><html>
<head>
<!-- PUT THIS TAG IN THE head SECTION -->
<script type="text/javascript" src="http://partner.googleadservices.com/gampad/google_service.js">
</script>
<script type="text/javascript">
  GS_googleAddAdSenseService("ca-pub-0719114306637522");
  GS_googleEnableAllServices();
</script>
<script type="text/javascript">
  GA_googleAddSlot("ca-pub-0719114306637522", "ino_300_250");
</script>
<script type="text/javascript">
  GA_googleFetchAds();
</script>
<!-- END OF TAG FOR head SECTION -->
</head>
<body>
<!-- PUT THIS TAG IN DESIRED LOCATION OF SLOT ino_300_250
     -->
<script type="text/javascript">
  GA_googleFillSlot("ino_300_250");
</script>
<!-- END OF TAG FOR SLOT ino_300_250
     -->
</body>
</html></div>

This is what causes me trouble...for me to fix this, I put in the javascript version of this which doesnt allow me to geotarget:

<div style = float:left><a href="http://www.ino.com/info/222/CD2369/&dp=0&l=0&campaignid=12"><img src="http://ino.directtrack.com/42/2369/222/" alt="" border="0"></a></div>

Thank you so much, please let me know if I can provide any additional information
i might see your problem
put this in your actual head section (<head> </head>)

<script type="text/javascript" src="http://partner.googleadservices.com/gampad/google_service.js">
</script>
<script type="text/javascript">
  GS_googleAddAdSenseService("ca-pub-0719114306637522");
  GS_googleEnableAllServices();
</script>
<script type="text/javascript">
  GA_googleAddSlot("ca-pub-0719114306637522", "ino_300_250");
</script>
<script type="text/javascript">
  GA_googleFetchAds();
</script>

Put this in the Ad module
<script type="text/javascript">
  GA_googleFillSlot("ino_300_250");
</script>

 
The way you are doing it is creating a whole new document inside a <div> tag which IE is probably choking on.
Avatar of mysmp

ASKER

nice idea...does this mean I have to edit the actual AD module to include the following?:
<script type="text/javascript">
 GA_googleFillSlot("ino_300_250");
</script>

And then the other piece of code would go into the GUI as I always enter it?
Avatar of mysmp

ASKER

btw...the Ad module is written in PHP and I have no idea how to edit it.  Can you tell me where I would need to put the code in this file?  This appears to be the main "Ad Module" file...its called ad.module
<?php
// $Id: ad.module,v 1.2.2.29.2.75 2008/05/31 15:34:51 jeremy Exp $
 
/**
 * @file
 * An advertising system for Drupal powered websites.
 *
 * Copyright (c) 2005-2008.
 *   Jeremy Andrews <jeremy@kerneltrap.org>.  All rights reserved.
 */
 
/**
 * Use this function to display ads from a specified group.
 *
 * @param $group
 *  The ad group tid to display ads from.
 * @param $quantity
 *  Optionally specify the number of unique ads to display.
 * @param $options
 *  Any number of options from this list:  hostid, nids.
 */
function ad($group = FALSE, $quantity = 1, $options = array()) {
  global $base_url;
 
  $adserve = variable_get('adserve', '');
  $adserveinc = variable_get('adserveinc', '');
  if (empty($adserve) || empty($adserveinc)) {
    // This is probably the first time ad() has been called.
    _ad_check_install();
    $adserve = variable_get('adserve', '');
    $adserveinc = variable_get('adserveinc', '');
  }
  if (!file_exists($adserve) || !file_exists($adserveinc)) {
    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');
    _ad_check_install();
    return(t('The ad module is <a href="@misconfigured">misconfigured</a>.', array('@misconfigured' => url('admin/content/ad/configure'))));
  }
 
  // Be sure a display method has been chosen.
  if (!isset($options['ad_display'])) {
    $options['ad_display'] = variable_get('ad_display', 'javascript');
  }
  $options['quantity'] = isset($quantity) ? $quantity : 1;
  if (!isset($options['tids'])) { 
    $options['tids'] = $group;
  }
  $options['cache'] = variable_get('ad_cache', 'none');
 
  switch ($options['ad_display']) {
    case 'raw':
      require_once(drupal_get_path('module', 'ad') .'/adserve.inc');
      $output = adserve_ad($options);
      break;
    case 'iframe':
      $display_variables = "m=iframe";
      // Fall through...
    case 'javascript':
    default:
      if ($display_variables) {
        $display_variables .= "&amp;q=$quantity";
      }
      else {
        $display_variables = "q=$quantity";
      }
      if ($hostid = $options['hostid']) {
        $display_variables .= "&amp;k=$hostid";
      }
      if ($options['cache'] != 'none') {
        // Allow external cache files to define additional display variables.
        $display_variables .= '&amp;c='. $options['cache'] . module_invoke('ad_cache_'. $options['cache'], 'adcacheapi', 'display_variables', array());
      }
      if ($nids = $options['nids']) {
        // Choose ads from the provided list of node Id's.
        $display_variables .= "&amp;n=$nids";
        $group = "nids-$nids";
      }
      else if ($tids = $options['tids']) {
        // Choose ads from the provided list of taxonomy terms.
        $display_variables .= "&amp;t=$tids";
        $group = "tids-$tids";
      }
      else {
        // Choose ads from the specified group.
        $display_variables .= "&amp;t=$group";
        $options['tids'] = $group;
      }
      $src = url("$base_url/$adserve?$display_variables");
      if ($options['ad_display'] == 'iframe') {
        // TODO: We need to know the IFrame size before it is displayed.  This
        // limits the flexibility of what can be displayed in these frames.
        // For now we'll have a global value, later we'll add per-group
        // over-rides.
        $append = 'frameborder="'. variable_get('ad_iframe_frameborder', 0) .'" ';
        $append .= 'scrolling="'. variable_get('ad_iframe_scroll', 'auto') .'" ';
        $append .= "name=\"$group\" ";
        if ($height = variable_get('ad_iframe_height', '')) {
          $append .= "height=\"$height\" ";
        }
        if ($width = variable_get('ad_iframe_width', '')) {
          $append .= "width=\"$width\" ";
        }
        $output = "<iframe src=\"$src\" $append></iframe>";
      }
      else {
        $output = "<script type=\"text/javascript\" src=\"$src\"></script>";
      }
      break;
  }
 
  if (user_access('show advertisements')) {
    return theme('ad_display', $group, $output);
  }
  else {
    return theme('ad_display', 'none', "<!-- Enable 'show advertisements' permission if you wish to display ads here. -->");
  }
}
 
/**
 * Function to display the actual advertisement to the screen.  Wrap it in a 
 * theme function to make it possible to customize in your own theme.
 */
function theme_ad_display($group, $display) {
  // The naming convention for the id attribute doesn't allow commas.
  $group = preg_replace('/[,]/', '', $group);
  return "\n<div class=\"advertisement\" id=\"group-$group\">$display</div>\n";
}
 
/**
 * Update click counter then redirect host to ad's target URL.
 */
function ad_redirect($aid, $group = NULL, $hostid = NULL) {
  global $user;
  if (function_exists('click_filter_status')) {
    $status = click_filter_status($aid, $hostid);
    if ($status == CLICK_VALID) {
      ad_statistics_increment($aid, 'click', $group, $hostid);
    }
  }
  else {
    // We're not filtering clicks, so all clicks are valid.
    ad_statistics_increment($aid, 'click', $group, $hostid);
    $status = 0;
  }
  // Allow source url to be passed in.
  if (!($url = $_GET['u']) || !valid_url($url)) {
    $url = referer_uri();
  }
  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, $_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT'], $group, $hostid, $url, time());
 
  // Determine where we're supposed to redirect the user.
  $adtype = db_result(db_query('SELECT adtype FROM {ads} WHERE aid = %d', $aid));
 
  $node->nid = $node->aid = $aid;
  $node->hostid = $hostid;
  $url = module_invoke('ad_'. $adtype, 'adapi', 'redirect', $node);
  if (isset($url)) {
    watchdog('ad', t('Clicked %type ad aid %aid hostid %hostid.', array('%type' => $adtype, '%aid' => $aid, '%hostid' => $hostid)));
    header('Location: '. $url);
  }
  else {
    watchdog('ad', t('Ad redirection failed for aid %aid hostid %hostid, failed to load destination URL. ', array('%aid' => $aid, '%hostid' => $hostid)));
    drupal_goto('');
  }
}
 
/**
 * Ad API Helper Function:
 * Append all necessary attributes to <a> tags.
 */
function ad_link_attributes() {
  $output = ad_link_target();
  $output .= ad_link_nofollow();
  return $output;
}
 
/**
 * Ad API Helper Function:
 * Append target="..." as globally configured.
 */
function ad_link_target() {
  return ' target="'. variable_get('ad_link_target', '_self') .'"';
}
 
/**
 * Ad API Helper Function:
 * Append rel="nofollow" if globally enabled.
 */
function ad_link_nofollow() {
  if (variable_get('ad_link_nofollow', 0)) {
    return ' rel="nofollow"';
  }
  return; 
}
 
/**
 * Increment action counter.
 */
function ad_statistics_increment($aid, $action, $group = NULL, $hostid = NULL) {
  // Update action statistics.
  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);
  // If column doesn't already exist, we need to add it.
  if (!db_affected_rows()) {
    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);
    // If another process already added this row our INSERT will fail, if so we
    // still need to increment it so we don't loose an action.
    if (!db_affected_rows()) {
      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);
    }
  }
 
  $event = array('aid' => $aid, 'action' => $action, 'hostid' => $hostid);
  module_invoke_all('adapi', 'statistics_increment', $event);
}
 
function ad_status_array($admin = TRUE) {
  if ($admin) {
    // status options for administrators
    return array(
      'pending' => t('This advertisement is currently waiting for administrative approval.'), 
      'approved' => t('This advertisement has been approved and is currently waiting to be administratively activated.'), 
      'active' => t('This advertisement is actively being displayed.'), 
      'offline' => t('This advertisement has been temporarily disabled by its owner and is not currently being displayed.'), 
      'unpublished' => t('This advertisement has been unpublished and is not currently being displayed.'), 
      'expired' => t('This advertisement has expired.'), 
      'denied' => t('This advertisement was refused by the site administrator, it will not be displayed.'));
  }
  else {
    // status options for advertisement owners
    return array(
      'active' => t('This advertisement is actively being displayed.'), 
      'offline' => t('This advertisement has been temporarily disabled and is not currently being displayed.'));
  }
}
 
/**
 * Calculate statistics for the given advertisements.
 * TODO: Introduce caching to make this more efficient.
 */
function ad_statistics($aid) {
  // Get global statistics.
  $statistics['global']['views'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view'", $aid));
  $statistics['global']['clicks'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click'", $aid));
 
  // No sense in making further queries if the ad has no global statistics.
  if (!$statistics['global']['views'] && !$statistics['global']['clicks']) {
    return $statistics;
  }
 
  // Get statistics for this year and last year.
  $this_year = date('Y000000');
  $last_year = date('Y') - 1 .'000000';
  $statistics['last_year']['views'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d AND date <= %d", $aid, $last_year, $this_year));
  $statistics['last_year']['clicks'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d AND date <= %d", $aid, $last_year, $this_year));
  $statistics['this_year']['views'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d", $aid, $this_year));
  $statistics['this_year']['clicks'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d", $aid, $this_year));
 
  // No sense in making further queries if the ad has no statistics this year.
  if (!$statistics['this_year']['views'] && !$statistics['this_year']['clicks']) {
    return $statistics;
  }
 
  // Get statistics for this month and last month.
  $this_month = date('Ym0000');
  $last_month = date('m') - 1;
  if ($last_month == 0) {
    $last_month = date('Y') - 1 .'120000';
  }
  else {
    $last_month = date('Y'). ($last_month < 10 ? '0' : '') . $last_month .'0000';
  }
  $statistics['last_month']['views'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d AND date <= %d", $aid, $last_month, $this_month));
  $statistics['last_month']['clicks'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d AND date <= %d", $aid, $last_month, $this_month));
  $statistics['this_month']['views'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d", $aid, $this_month));
  $statistics['this_month']['clicks'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d", $aid, $this_month));
 
  // No sense in making further queries if the ad has no statistics this month.
  if (!$statistics['this_month']['views'] && !$statistics['this_month']['clicks']) {
    return $statistics;
  }
 
  // Get statistics for this week.
  $this_week_start = date('Ymd00', time() - 60*60*24*6);
  $statistics['this_week']['views'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date > %d", $aid, $this_week_start));
  $statistics['this_week']['clicks'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date > %d", $aid, $this_week_start));
 
  // No sense in making further queries if the ad has no statistics this week.
  if (!$statistics['this_week']['views'] && !$statistics['this_week']['clicks']) {
    return $statistics;
  }
 
  // Get statistics for yesterday and today.
  $yesterday_start = date('Ymd00', time() - 60*60*24);
  $yesterday_end = date('Ymd24', time() - 60*60*24);
  $today_start = date('Ymd00', time());
  $statistics['yesterday']['views'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d AND date <= %d", $aid, $yesterday_start, $yesterday_end));
  $statistics['yesterday']['clicks'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d AND date <= %d", $aid, $yesterday_start, $yesterday_end));
  $statistics['today']['views'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d", $aid, $today_start));
  $statistics['today']['clicks'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d", $aid, $today_start));
 
  // No sense in making further queries if the ad has no statistics today.
  if (!$statistics['today']['views'] && !$statistics['today']['clicks']) {
    return $statistics;
  }
 
  // Get statistics for this hour and the last hour.
  $last_hour = date('YmdH', time() - 60*60);
  $this_hour = date('YmdH', time());
  $statistics['last_hour']['views'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date = %d", $aid, $last_hour));
  $statistics['last_hour']['clicks'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date = %d", $aid, $last_hour));
  $statistics['this_hour']['views'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date = %d", $aid, $this_hour));
  $statistics['this_hour']['clicks'] = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date = %d", $aid, $this_hour));
 
  return $statistics;
}
 
/**
 * Display the status of the currently viewed ad.
 */
function theme_ad_status_display($node) {
  $status_array = ad_status_array();
  $output  = '<div class="adstatus">';
  $output .= '<p>'. t($status_array["$node->adstatus"]) .'</p>';
  switch ($node->adstatus) {
    case 'approved':
      if ($node->autoactivate) {
        $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>';
      }
      break;
    case 'active':
      $activated = db_result(db_query("SELECT activated FROM {ads} WHERE aid = %d", $node->nid));
      if ($activated) {
        $output .= '<p>'. t('This advertisement has been active since %date.', array('%date' => format_date($activated, 'large'))) .'</p>';
      }
      if ($node->autoexpire) {
        $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>';
      }
      if ($node->maxviews) {
        $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)));
        $output .= '<p>'. t('This advertisement will expire after %left more views.', array('%left' => $node->maxviews - $views)) .'</p>';
      }
      if ($node->maxclicks) {
        $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)));
        $output .= '<p>'. t('This advertisement will expire after %left more clicks.', array('%left' => $node->maxclicks - $clicks)) .'</p>';
      }
      break;
    case 'expired':
      $expired = db_result(db_query("SELECT expired FROM {ads} WHERE aid = %d", $node->nid));
      if ($expired) {
        $output .= '<p>'. t('This advertisement expired %date.', array('%date' => format_date($expired, 'large'))) .'</p>';
      }
      break;
  }
  $output .= '</div>';
  return theme('box', t('Status'), $output);
}
 
function theme_ad_statistics_display($statistics) {
  $headers = array('', t('Views'), t('Clicks'), t('Click-thru'));
  $rows = array();
 
  $data = array('this_hour' => t('This hour'), 'last_hour' => t('Last hour'), 'today' => t('Today'), 'yesterday' => t('Yesterday'), 'this_week' => t('Last seven days'), 'last_week' => t('Last week'), 'this_month' => t('This month'), 'last_month' => t('Last month'), 'this_year' => t('This year'), 'last_year' => t('Last year'), 'global' => t('All time'));
 
  foreach ($data as $key => $value) {
    if ($statistics[$key]['views'] || $statistics[$key]['clicks'] || $key == 'global') {
      $rows[] = array(
        array('data' => $value),
        array('data' => (int)$statistics[$key]['views']),
        array('data' => (int)$statistics[$key]['clicks']),
        array('data' => $statistics[$key]['views'] ? sprintf('%1.2f', ((int)$statistics[$key]['clicks'] / (int)$statistics[$key]['views']) * 100) .'%' : '0.00%'),
      );
    }
  }
  return theme('box', t('Statistics'), theme('table', $headers, $rows));
}
 
/****************
 * Drupal hooks *
 ****************/
 
/**
 * Implementation of hook_help().
 */
function ad_help($path) {
  switch ($path) {
    case 'admin/help#ad':
      $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>';
      break;
  }
  return $output;
}
 
/**
 * Drupal _cron hook.
 */
function ad_cron() {
  if (time() - variable_get('ad_cron_timestamp', 0) >= 60) {
    // Locate ads that need to be activated or expired.
    $result = db_query('SELECT aid, adstatus, adtype, autoactivate, autoactivated, autoexpire, autoexpired FROM {ads} WHERE autoactivate != 0 OR autoexpire != 0');
    while ($ad = db_fetch_object($result)) {
      switch ($ad->adstatus) {
        case 'approved': {
          // See if this ad is ready to be activated.
          if ($ad->autoactivate && $ad->autoactivate <= time()) {
            $node = node_load($ad->aid);
 
            // Activate the ad.
            db_query("UPDATE {ads} SET adstatus = 'active', autoactivate = 0, autoactivated = %d, activated = %d WHERE aid = %d", time(), time(), $ad->aid);
            ad_statistics_increment($ad->aid, 'autoactivated');
            ad_statistics_increment($ad->aid, 'active');
 
            watchdog('ad', t('Automatically activated ad %title with nid %nid.', array('%title' => $node->title, '%nid' => $node->nid)));
 
            // Allow modules to do special processing to automatically
            // activated advertisements.
            module_invoke('ad_'. $ad->adtype, 'adapi', 'autoactivate', $node);
          }
          else if (!$ad->autoactivate) {
            // Once daily warn that there's an ad stuck in approved state.
            if (time() - variable_get("ad_autoactivate_warning_$ad->aid", 0) >= 8600) {
              watchdog('ad', t('Warning: ad %title with nid %nid in approved state has no autoactivate date set.', array('%title' => $node->title, '%nid' => $node->nid)));
              variable_set("ad_autoactivate_warning_$ad->aid", time());
            }
          }
          break;
        }
        case 'active': {
          // See if this ad is ready to be activated.
          if ($ad->autoexpire && $ad->autoexpire <= time()) {
            $node = node_load($ad->aid);
 
            // Expire the ad.
            db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $ad->aid);
            ad_statistics_increment($ad->aid, 'autoexpired');
            ad_statistics_increment($ad->aid, 'expired');
 
            watchdog('ad', t('Automatically expired ad %title with nid %nid.', array('%title' => $node->title, '%nid' => $node->nid)));
 
            // Allow modules to do special processing to automatically
            // activated advertisements.
            module_invoke('ad_'. $ad->adtype, 'adapi', 'autoexpire', $node);
          }
          else if (!$ad->autoexpire) {
            // Ad is already activated, but has autoactivate timestamp set.
            db_query("UPDATE {ads} SET autoactivate = 0 WHERE aid = %d", $ad->aid);
          }
          break;
        }
        default:
          $node = node_load($ad->aid);
          db_query('UPDATE {ads} SET autoactivate = 0, autoexpire = 0 WHERE aid = %d', $ad->aid);
          watchdog('ad', t('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)));
      }
    }
    variable_set('ad_cron_timestamp', time());
  }
}
 
/**
 * Drupal _perm hook.  Establishes permissions used by this module.
 *
 * @return  An array of permissions used by this module.
 */
function ad_perm() {
  return ( 
          array('administer advertisements',
                'create advertisements',
                'edit own advertisements',
                'show advertisements')
         );
}
 
/**
 */
function ad_node_info() {
  return array('ad' => array(
    'name' => t('Advertisement'),
    'module' => 'ad',
    'description' => t('Advertisements can be randomly displayed to visitors of your website.'),
    'help' => t('Advertisements can be randomly displayed to visitors of your website.'),
  ));
}
 
/**
 */
function ad_access($op, $node) {
  global $user;
 
  if ($op == 'create') {
    return user_access('create advertisements');
  }
 
  if ($op == 'update' || $op == 'delete') {
    return (user_access('administer advertisements') || 
           (ad_is_owner($node->nid) && user_access('edit own advertisements')));
  }
}
 
/**
 * Drupal _form hook.
 */
function ad_form(&$node) {
  $form = array();
  $edit = $_POST['edit'];
 
  $type = arg(3);
  if (function_exists("ad_$type". '_type')) {
    $adtype = $type;
  }
  else {
    $adtype = $node->adtype;
  }
 
  $form['aid'] = array(
    '#type' => 'value',
    '#value' => $node->nid,
  );
 
  $form['title'] = array(
    '#type' => 'textfield',
    '#title' => t('Title'), 
    '#required' => TRUE, 
    '#default_value' => $node->title,
  );
  $form['body_filter']['body'] = array(
    '#type' => 'textarea', 
    '#title' => t('Description'), 
    '#default_value' => $node->body, 
    '#rows' => 3
  );
  $form['body_filter']['format'] = filter_form($node->format);
 
  // determine the current ad type
  if (!isset($adtype)) {
    $adtypes = module_invoke_all('adapi', 'type', array());
    switch (sizeof($adtypes)) {
      case 0:
        drupal_set_message(t('At least one ad type module must be enabled before you can create advertisements.  For example, try %enabling the ad_text or ad_image module.', array('%enabling' => l('enabling', 'admin/modules'))), 'error');
        break;
      case 1:
        $adtype = $adtypes[0];
        break;
      default:
        if (arg(0) == 'node' && arg(1) == 'add' && arg(2) == 'ad') {
          $adtype = arg(3) ? arg(3) : $edit['adtype'];
          $form['adtype'] = array(
            '#type' => 'radios', 
            '#title' => t('Style of ad'), 
            '#options' => drupal_map_assoc($adtypes), 
            '#default_value' => $adtype ? $adtype : $adtypes[0], 
            '#required' => TRUE, 
            '#description' => t('Select the type of ad that you wish to create from the above options.')
          );
        }
        break;
    }
  }
 
  // display type-specific options
  if (isset($adtype)) {
    $elements = module_invoke('ad_'. $adtype, 'adapi', 'form', $node);
    foreach ($elements as $element => $values) {
      $form["$element"] = $values;
    }
    $form['adtype'] = array(
      '#type' => 'hidden', 
      '#value' => $adtype,
    );
  }
 
  if (user_access('administer advertisements')) {
    // admins can set any status on advertisements
    $form['adstatus'] = array(
      '#type' => 'fieldset', 
      '#title' => t('Status'), 
      '#collapsible' => TRUE
    );
    foreach (ad_status_array() as $status => $description) {
      $form['adstatus']["ad$status"] = array(
        '#type' => 'radio', 
        '#title' => t("$status"), 
        '#return_value' => $status, 
        '#default_value' => $node->adstatus ? $node->adstatus : t('pending'),
        '#description' => "$description", 
        '#parents' => array("adstatus")
      );
    }
  }
  else if (ad_adaccess($node->nid, 'manage status')) {
    if (!$node->adstatus || $node->adstatus == 'pending') {
      $adstatus = ad_status_array();
      $node->adstatus = t('pending');
      $form['adstatus'] = array(
        '#type' => 'fieldset', 
        '#title' => t('Status'), 
        '#collapsible' => TRUE
      );
      $form['adstatus']['display'] = array(
        '#type' => 'markup', 
        '#value' => '<p><b>'. t('Status') .':</b> '. t($node->adstatus) .'<br />'. t($adstatus["$node->adstatus"]),
      );
      $form['adstatus']['adpending'] = array(
        '#type' => 'value', 
        '#value' => $node->adstatus
      );
    }
    else {
      $adstatus = ad_status_array(FALSE);
      // display status options
      $form['adstatus'] = array(
        '#type' => 'fieldset', 
        '#title' => t('Status'), 
        '#collapsible' => TRUE
      );
      foreach ($adstatus as $status => $description) {
        $form['adstatus']["ad$status"] = array(
          '#type' => 'radio', 
          '#title' => t("$status"), 
          '#return_value' => $status, 
          '#default_value' => $node->adstatus ? $node->adstatus : t('pending'), 
          '#description' => "$description", 
          '#parents' => array("adstatus")
        );
      }
    }
  }
  else {
    $adstatus = ad_status_array();
    if (!($node->adstatus)) {
      $node->adstatus = t('pending');
    }
    $form['ad_adstatus'] = array(
      '#type' => 'fieldset', 
      '#title' => t('Status'), 
      '#collapsible' => TRUE
    );
    $form['ad_adstatus']['adstatus_display'] = array(
      '#type' => 'markup', 
      '#value' => '<p><b>'. t('Status') .':</b> '. t($node->adstatus) .'<br />'. t($adstatus["$node->adstatus"]),
    );
    $form['adstatus'] = array(
      '#type' => 'value', 
      '#value' => $node->adstatus
    );
  }
 
  if (ad_adaccess($node->nid, 'access statistics')) {
    // display statistics
    $form['statistics'] = array(
      '#type' => 'fieldset', 
      '#title' => t('Statistics'), 
      '#collapsible' => TRUE,
    );
  
    $form['statistics']['data'] = array(
      '#type' => 'markup',
      '#prefix' => '<div>',
      '#suffix' => '</div>',
      '#value' => theme('ad_statistics_display', ad_statistics($node->nid)),
    );
  }
  
  // display scheduling options
  $form['schedule'] = array(
    '#type' => 'fieldset', 
    '#title' => t('Scheduling'), 
    '#collapsible' => TRUE,
    // Collapse if there isn't any scheduling data set.
    '#collapsed' => ($node->autoactivate || $edit['autoactivate'] ||
                     $node->autoexpire || $edit['autoexpire'] ||
                     $node->maxviews || $edit['maxviews'] ||
                     $node->maxclicks || $edit['maxclicks']) 
                     ? FALSE : TRUE,
  );
 
  if (ad_adaccess($node->nid, 'manage status')) {
    $form['schedule']['current'] = array( 
      '#type' => 'markup', 
      '#prefix' => '<div>',
      '#suffix' => '</div>',
      '#value' => t('The current date and time is "%date".', array('%date' => format_date(time(), 'custom', 'F j, Y H:i')))
    );
    $form['schedule']['autoactivate'] = array( 
      '#type' => 'textfield', 
      '#title' => t('Automatically activate ad'), 
      '#required' => FALSE, 
      '#default_value' => $node->autoactivate ? format_date((int)$node->autoactivate, 'custom', 'F j, Y H:i') : '', 
      '#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.')
    );
  }
 
  if (user_access('administer advertisements')) {
    // admins can expire advertisements
    $form['schedule']['autoexpire'] = array(
      '#type' => 'textfield', 
      '#title' => t('Automatically expire ad'), 
      '#required' => FALSE, 
      '#default_value' => $node->autoexpire ? format_date((int)$node->autoexpire, 'custom', 'F j, Y H:i') : '', 
      '#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.')
    );
    $form['schedule']['maxviews'] = array(
      '#type' => 'textfield', 
      '#title' => t('Maximum views'), 
      '#required' => FALSE, 
      '#size' => 10,
      '#maxlength' => 11,
      '#default_value' => $node->maxviews,
      '#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 views, leave this field set to %zero.', array('%zero' => '0')),
    );
    $form['schedule']['maxclicks'] = array(
      '#type' => 'textfield', 
      '#title' => t('Maximum clicks'), 
      '#required' => FALSE, 
      '#size' => 10,
      '#maxlength' => 11,
      '#default_value' => $node->maxclicks,
      '#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')),
    );
  }
  else {
    // display expiration time
    $form['schedule']['autoexpire_display'] = array(
      '#type' => 'markup', 
      '#prefix' => '<div>',
      '#suffix' => '</div>',
      '#value' => theme('ad_status_display', $node),
    );
    $form['schedule']['autoexpire'] = array(
      '#type' => 'hidden', 
      '#value' => $node->autoexpire
    );
  }
 
  return $form;
}
 
/**
 * Drupal _form_alter() hook.
 */
function ad_form_alter($form_id, &$form) {
  if ($form_id == 'taxonomy_form_vocabulary') {
    // Remove taxonomy form options not applicable for ad groups.
    if ($form['vid']['#value'] == _ad_get_vid()) {
      $form['help_ad_vocab'] = array(
        '#value' => t('This vocabulary was automatically created for use by the ad module.  Only applicable options are available.'),
        '#weight' => -1
      );
      $form['nodes']['ad'] = array(
        '#type' => 'checkbox',
        '#title' => t('ad group'),
        '#value' => 1,
        '#attributes' => array('disabled' => ''),
        '#description' => t('Type %type is required to use this vocabulary.', array('%type' => t('ad group')))
      );
      $form['tags']['#description'] = t('If enabled, ads are categorized by typing ad group names instead of choosing them from a list.');
      $form['multiple']['#description'] = t('If enabled, allows ads to have more than one ad group (always true for free tagging).');
      $form['required']['#description'] = t('If enabled, every ad <strong>must</strong> be assigned to at least one ad group.');
      $form['hierarchy'] = array('#type' => 'value', '#value' => 0);
      unset($form['relations']);
    }
    else {
      unset($form['nodes']['ad']);
    }
  }
  else if ($form_id == 'taxonomy_form_term') {
    if ($form['vid']['#value'] == _ad_get_vid()) {
      $form['name']['#title'] = t('Ad group name');
      $form['name']['#description'] = t('The name for this ad group.  Example: "Linux".');
      $form['description']['#description'] = t('A description of the ad group.');
      $form['description']['#required'] = TRUE;
      $form['weight']['#description'] = t('In listings, the heavier ad groups will sink and the lighter ad groups will be positioned nearer the top.');
      unset($form['synonyms']);
    }
  }
}
 
/**
 * Drupal _nodeapi hook.
 */
function ad_nodeapi(&$node, $op, $teaser, $page) {
  global $user;
 
  switch ($op) {
 
    case 'load':
      $ad = db_fetch_array(db_query('SELECT * FROM {ads} WHERE aid = %d', $node->nid));
      $adtype = module_invoke('ad_'. $ad['adtype'], 'adapi', 'load', $ad);
      if (is_array($adtype)) {
        return array_merge($ad, $adtype);
      }
      else {
        return $ad;
      }
      break;
 
    case 'insert':
      if ($node->adtype) {
        if ($node->status != 1 && $node->adstatus == 'active') {
          $node->adstatus = t('unpublished');
        }
        $activated = $node->adstatus == 'active' ? time() : 0;
        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", NULL, NULL, TRUE), $node->autoactivate ? strtotime($node->autoactivate) : '', $node->autoexpire ? strtotime($node->autoexpire) : '', $activated, (int)$node->maxviews, (int)$node->maxclicks);
        ad_owners_add($node->nid, $node->uid);
        ad_host_id_create($node->uid);
        ad_statistics_increment($node->nid, 'create');
      }
      break;
 
    case 'update':
      if ($node->adtype) {
        $ad = db_fetch_object(db_query('SELECT * FROM {ads} WHERE aid = %d', $node->nid));
        // Ad must be in approved state to be able to autoactivate it.
        if ($node->adstatus != 'approved' && $node->autoactivate) {
          if ($node->adstatus == 'active') {
            // This ad is already active, no need to autoactivate it.
            $node->autoactivate = 0;
          }
          else {
            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');
          }
        }
        // If this node has been upublished, the ad should no longer be active.
        if ($node->status != 1 && $node->adstatus == 'active') {
          $node->adstatus = t('unpublished');
        }
        // If a previously unpublished node has been published, reactivate the
        // the ad.
        else if ($node->status == 1 && $node->adstatus == 'unpublished') {
          $node->adstatus = t('active');
          // Special "publish" event, may as well track it even though we'll
          // next also record an "active" event.
          ad_statistics_increment($node->nid, 'publish');
        }
        // Check if ad is being manually activated.
        if ($ad->adstatus != 'active' && $node->adstatus == 'active') {
          $activated = time();
        }
        // Check if ad is being manually expired.
        else if ($ad->status != 'expired' && $node->adstatus == 'expired') {
          // Ad has been manually expired.
          $expired = time();
        }
        // Ad has not been manually activated or expired, preserve timestamps.
        else {
          $activated = $ad->activated;
          $expired = $ad->expired;
        }
        // Ad status has changed, record the event.
        if ($ad->adstatus != $node->adstatus) {
          ad_statistics_increment($node->nid, $node->adstatus);
        }
        // Update ads table with new information.
        db_query("UPDATE {ads} SET uid = %d, adstatus = '%s', adtype = '%s', autoactivate = %d, autoexpire = %d, activated = %d, maxviews = %d, maxclicks = %d, expired = %d WHERE aid = %d", $node->uid, $node->adstatus, $node->adtype, $node->autoactivate ? strtotime($node->autoactivate) : '', $node->autoexpire ? strtotime($node->autoexpire) : '', $activated, (int)$node->maxviews, (int)$node->maxclicks, $expired, $node->nid);
        // Be sure ad owner has at least default ad permissions.
        ad_owners_add($node->nid, $node->uid);
        ad_host_id_create($node->uid);
        ad_statistics_increment($node->nid, 'update');
      }
      break;
 
    case 'delete':
      db_query("DELETE FROM {ads} WHERE aid = %d", $node->nid);
      db_query("DELETE FROM {ad_statistics} WHERE aid = %d", $node->nid);
      // Clean up ad_permissions and any other per-ad tables.
      $result = db_query('SELECT oid, uid FROM {ad_owners} WHERE aid = %d', $node->nid);
      while ($id = db_fetch_object($result)) {
        db_query('DELETE FROM {ad_permissions} WHERE oid = %d', $id->oid);
        $owner = user_load(array('uid' => $id->uid));
        // Tell plug-in modules to clean up.
        module_invoke_all('adowners', 'remove', $id->oid, $owner);
      }
      db_query('DELETE FROM {ad_owners} WHERE aid = %d', $node->nid);
      // All that's left of the ad is a single timestamp as to when it was 
      // deleted.
      ad_statistics_increment($node->nid, 'delete');
      break;
 
    case 'view':
      if ($node->adtype) {
        $node = node_prepare($node, $teaser);
        $node->content['body'] = array(
          '#value' => $teaser ? $node->teaser : theme('node_ad', $node, $page),
          '#weight' => 1,
        );
      }
      break;
  }
  // Allow ad type module to act on nodeapi events.  The adapi hook provides 
  // access to additional variables not available in the nodeapi hook.
  if ($node->adtype) {
    // Don't use module_invoke, as in pre-PHP5 the changes to $node won't be
    // passed back.
    $function = "ad_$node->adtype" .'_adapi';
    if (function_exists($function)) {
      $function($op, $node);
    }
  }
  // Allow ad cache module to act on nodeapi events.
  $cache = variable_get('ad_cache', 'none');
  if ($cache != 'none') {
    $function = "ad_cache_$cache" .'_adcacheapi';
    if (function_exists($function)) {
      $function($op, $node);
    }
  }
}
 
function theme_node_ad($node, $yield_form = TRUE) {
  $output = '';
  if (ad_adaccess($node->nid, 'access statistics')) {
    $output = theme('ad_status_display', $node);
    $output .= theme('ad_statistics_display', ad_statistics($node->nid));
  }
  if (ad_adaccess($node->nid, 'access click history')) {
    $header = array(
      array('data' => t('Time'), 'field' => 'timestamp', 'sort' => 'desc'),
      array('data' => t('IP address'), 'field' => 'hostname'),
      array('data' => t('URL where clicked'), 'field' => 'url'),
    );
    if (function_exists('click_filter_status_text') && user_access('view filtered clicks')) {
      $header[] = array('data' => t('Status'), 'field' => 'status');
    }
    $header[] = array('data' => t(' '));
 
    if ($node->nid) {
      $sql = "SELECT cid, timestamp, uid, status, hostname, url FROM {ad_clicks} WHERE aid = $node->nid";
      $sql .= tablesort_sql($header);
      $result = pager_query($sql, 25);
 
      while ($ad = db_fetch_object($result)) {
        if (module_exists('click_filter') && $ad->status != CLICK_VALID) {
          // Only show filtered clicks to users with permission to view them.
          if (!user_access('view filtered clicks')) {
            continue;
          }
        }
        if (strlen($ad->url) > 40) {
          $url = substr($ad->url, 0, 37) .'...';
        }
        else {
          $url = $ad->url;
        }
        $row = array();
        $click_user = user_load(array('uid' => $ad->uid));
        $row[] = format_date($ad->timestamp, 'custom', 'M j H:i');
        $row[] = $ad->hostname;
        $row[] = l($url, $ad->url);
        if (function_exists('click_filter_status_text') && user_access('view filtered clicks')) {
          $row[] = click_filter_status_text($ad->status);
        }
        $row[] = '['. l('details', "node/$node->nid/details/$ad->cid") .']';
        $rows[] = $row;
      }
 
      $click_history = theme('table', $header, $rows);
      $click_history .= theme('pager', NULL, 25, 0);
      $output .= theme('box', t('Click history'), $click_history);
    }
  }
  return $output;
}
 
function ad_click_details($nid, $cid) {
  drupal_set_title(t('Click details'));
  $node = node_load($nid);
  drupal_set_breadcrumb(array(l(t('Home'), NULL), l($node->title, "node/$node->nid")));
  if ($click = db_fetch_object(db_query('SELECT * FROM {ad_clicks} WHERE cid = %d', $cid))) {
    $ad = node_load($click->aid);
    $rows = array(
      array(
        array('data' => t('Time'), 'header' => TRUE),
        format_date($click->timestamp, 'custom', 'D F j, Y h:i a'),
      ),
      array(
        array('data' => t('IP Address'), 'header' => TRUE),
        $click->hostname,
      ),
      array(
        array('data' => t('User Agent'), 'header' => TRUE),
        $click->user_agent,
      ),
      array(
        array('data' => t('URL'), 'header' => TRUE),
        l($click->url, $click->url),
      ),
      array(
        array('data' => t('Advertisement'), 'header' => TRUE),
        $ad->ad,
      )
    );
    if (function_exists('click_filter_status_text') && user_access('view filtered clicks')) {
      switch ($click->status) {
        case 0:
        default:
          $status = t('Not valid: this click has not been counted for unknown reasons.  This is an unexpected error.');
          break;
        case 1:
          $status = t('Valid: this is a valid click.');
          break;
        case 2:
          $status = t('Not valid: this click has not been counted because another click by the same IP address was already counted.');
          break;
        case 3:
          $status = t('Not valid: this click has not been counted because it was generated by an owner of the advertisement.');
          break;
        case 4:
          $status = t('Not valid: this click has not been counted because it was generated by a user in a filtered role.');
          break;
        case 5:
          $status = t('Not valid: this click has not been counted because it was generated by an automated "bot".');
          break;
      }
      $rows[] = array(array('data' => t('Status'), 'header' => TRUE), $status);
    }
    $output = theme('table', array(), $rows, $attributes);
  }
  return $output;
}
 
function ad_adapi($op, $node = NULL) {
  switch ($op) {
    case 'permissions':
      return array('access statistics', 'access click history', 'manage status', 'manage owners');
      break;
  }
}
 
/**
 * Implementation of hook_menu().
 */
function ad_menu($may_cache) {
  global $user;
  $items = array();
 
  if ($may_cache) {
    // menu items
    $items[] = array('path' => 'admin/content/ad',
                     'title' => t('Ads'),
                     'callback' => 'ad_admin_list',
                     'access' => user_access('administer advertisements'),
                     'description' => t('Configure and manage your advertising system.'));
 
    // tabs
    $items[] = array('path' => 'admin/content/ad/list',
                     'title' => t('List'),
                     'callback' => 'ad_admin_list',
                     'type' => MENU_DEFAULT_LOCAL_TASK);
    $items[] = array('path' => 'admin/content/ad/statistics',
                     'title' => t('Statistics'),
                     'callback' => 'drupal_get_form',
                     'callback arguments' => array('ad_admin_statistics'),
                     'type' => MENU_LOCAL_TASK,
                     'weight' => 1);
    $items[] = array('path' => 'admin/content/ad/configure',
                     'title' => t('Settings'),
                     'callback' => 'drupal_get_form',
                     'callback arguments' => array('ad_admin_configure_settings'),
                     'type' => MENU_LOCAL_TASK,
                     'weight' => 3);
    $items[] = array('path' => 'admin/content/ad/groups',
                     'title' => t('Groups'),
                     'callback' => 'ad_admin_groups_list',
                     'type' => MENU_LOCAL_TASK,
                     'weight' => 5);
 
    // groups sub tabs
    $items[] = array('path' => 'admin/content/ad/groups/list',
                     'title' => t('List'),
                     'callback' => 'ad_admin_groups_list',
                     'type' => MENU_DEFAULT_LOCAL_TASK, 
                     'weight' => 0);
    $items[] = array('path' => 'admin/content/ad/groups/add', 
                     'title' => t('Create group'),
                     'callback' => 'drupal_get_form',
                     'callback arguments' => array('ad_admin_group_form'),
                     'type' => MENU_LOCAL_TASK,
                     'weight' => 3);
 
    // configure sub tabs
    $items[] = array('path' => 'admin/content/ad/configure/global',
                     'title' => t('Global settings'),
                     'callback' => 'drupal_get_form',
                     'callback arguments' => array('ad_admin_configure_settings'),
                     'type' => MENU_DEFAULT_LOCAL_TASK,
                     'weight' => 0);
    $items[] = array('path' => 'node/add/ad',
                     'title' => t('Ad'),
                     'callback' => 'ad_add',
                     'access' => user_access('create advertisements'));
 
    $adtypes = module_invoke_all('adapi', 'type', array());
    foreach ($adtypes as $adtype) {
      $items[] = array(
       'path' => 'node/add/ad/'. $adtype,
       'title' => t('!type advertisement', array('!type' => t($adtype))),
       'access' => user_access('create advertisements'),
      );
    }
  }
  else {
    // callbacks
    if (arg(0) == 'ad' && arg(1) == 'redirect' && is_numeric(arg(2))) {
      $aid = preg_replace('/[^0-9]/', '', arg(2));
      $group = preg_replace('/[^0-9,nt]/', '', arg(3));
      $hostid = preg_replace('/[^0-9a-f]/', '', arg(4));
      $items[] = array('path' => "ad/redirect/$aid",
                       'access' => user_access('show advertisements'),
                       'type' => MENU_CALLBACK, 
                       'callback' => 'ad_redirect',
                       'callback arguments' => array($aid, $group, $hostid));
    }
    elseif (arg(2) == 'ad' && arg(3) == 'groups' && is_numeric(arg(4))) {
      if ($term = taxonomy_get_term(arg(4))) {
        $items[] = array('path' => "admin/content/ad/groups/$term->tid/edit", 
                         'title' => t('edit'),
                         'callback' => 'drupal_get_form',
                         'callback arguments' => array(
                                                   'ad_admin_group_form', 
                                                   (array)$term),
                         'access' => user_access('administer advertisements'),
                         'type' => MENU_CALLBACK,
                         'weight' => 1);
        $items[] = array('path' => "admin/content/ad/groups/$term->tid/delete", 
                         'title' => t('delete'),
                         'callback' => 'drupal_get_form',
                         'callback arguments' => array(
                                                   'ad_confirm_group_delete', 
                                                   (array)$term),
                         'access' => user_access('administer advertisements'),
                         'type' => MENU_CALLBACK,
                         'weight' => 2);
      }
    }
    elseif (arg(0) == 'node' && is_numeric(arg(1)) && ad_adaccess(arg(1), 'manage owners')) {
      $node = node_load(arg(1));
      if ($node->adtype) {
        $items[] = array('path' => "node/$node->nid/adowners",
                         'access' => ad_adaccess($node->nid, 'manage owners'),
                         'title' => t('Ad owners'),
                         'callback' => 'ad_owners_overview',
                         'callback arguments' => array($node),
                         'type' => MENU_LOCAL_TASK,
                         'weight' => 5);
        $items[] = array('path' => "node/$node->nid/adowners/list",
                         'access' => ad_adaccess($node->nid, 'manage owners'),
                         'title' => t('List'),
                         'type' => MENU_DEFAULT_LOCAL_TASK,
                         'weight' => 0);
        if (is_numeric(arg(3))) {
          $uid = arg(3);
          $ad_user = user_load(array('uid' => $uid));
          $items[] = array('path' => "node/$node->nid/adowners/$uid/permissions",
                           'title' => t('!owner\'s permissions', array('!owner' => $ad_user->name)),
                           'access' => ad_adaccess($node->nid, 'manage owners'),
                           'callback' => 'drupal_get_form',
                           'callback arguments' => array('ad_owner_permissions', $node->nid, $uid),
                           'type' => MENU_LOCAL_TASK,
                           'weight' => 2);
          $items[] = array('path' => "node/$node->nid/adowners/$uid/remove",
                           'callback' => 'drupal_get_form',
                           'callback arguments' => array('ad_owner_remove', $node->nid, $uid),
                           'type' => MENU_CALLBACK,
                           'weight' => 6);
        }
        else {
          $items[] = array('path' => "node/$node->nid/adowners/add",
                           'access' => ad_adaccess($node->nid, 'manage owners'),
                           'title' => t('Add'),
                           'callback' => 'drupal_get_form',
                           'callback arguments' => array('ad_owners_add_form', $node),
                           'type' => MENU_LOCAL_TASK,
                           'weight' => 4);
        }
      }
    }
    if (is_numeric($nid = arg(1)) && is_numeric($cid = arg(3))) {
      $items[] = array(
        'path' => "node/$nid/details/$cid",
        'title' => t('Click details'),
        'callback' => 'ad_click_details',
        'callback arguments' => array($nid, $cid),
        'type' => MENU_CALLBACK
      );
    }
  }
 
  return $items;
}
 
/**
 * Drupal _block hook.
 */
function ad_block($op = 'list', $delta = 0, $edit = array()) {
  switch ($op) {
    case 'list':
      $blocks = array();
      $groups = ad_groups_list();
      foreach ($groups as $tid => $name) {
        $blocks[$tid]['info'] = t('ad group: @name', array('@name' => $name));
      }
      return $blocks;
    case 'configure':
      $form["ad_block_quantity_$delta"] = array(
        '#type' => 'select',
        '#title' => t('Number of ads'),
        '#default_value' => variable_get("ad_block_quantity_$delta", 1),
        '#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)),
        '#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.'),
      );
      return $form;
    case 'save':
      variable_set("ad_block_quantity_$delta", $edit["ad_block_quantity_$delta"]);
      break;
    case 'view':
      $groups = ad_groups_list();
      $block['content'] = ad($delta, variable_get("ad_block_quantity_$delta", 1));
      return $block;
  }
}
 
/****/
 
/**
 * Present a list of ad types to choose from.
 */
function ad_add() {
  global $user;
 
  $edit = isset($_POST['edit']) ? $_POST['edit'] : '';
  $adtypes = module_invoke_all('adapi', 'type', array());
  if (arg(3) && is_array($adtypes) && in_array(arg(3), array_keys($adtypes))) {
    $adtype = arg(3);
 
    $node = array(
      'uid' => $user->uid,
      'name' => $user->name,
      'type' => 'ad',
      'adtype' => $adtype,
    );
 
    foreach (array('title', 'teaser', 'body') as $field) {
      if ($_GET['edit'][$field]) {
        $node[$field] = $_GET['edit'][$field];
      }
    }
    drupal_set_title(t('Submit %name', array('%name' => $adtype)));
    $output = drupal_get_form('ad_node_form', $node);
  }
  else {
    $output = t('Choose from the following available advertisement types:');
    $output .= '<dl>';
    if (sizeof($adtypes) == 1) {
      drupal_goto('node/add/ad/'. $adtypes[0]);
    }
    else if (sizeof($adtypes)) {
 
      foreach ($adtypes as $type) {
        $output .= '<dt>'. l(t('!type advertisement', array('!type' => $type)), "node/add/ad/$type") .'</dt>';
        // Bugfix #166097: don't array_pop the module_invoke_all directly.
        // See: http://drupal.org/node/166097
        $help = module_invoke_all('help', 'node/add/ad#'. $type);
        $output .= '<dd>'. array_pop($help) .'</dd>';
      }
    }
    else {
      $output .= '<dt>'. t('There are no advertisement types available.') .'</dt>';
    }
    $output .= '</dl>';
  }
 
  return $output;
}
 
/**
 * TODO: Make this themeable.
 * TODO: Group permissions by module.
 * TODO: Allow modules to define default value for permission.
 */
function ad_owners_overview($node) {
  // Be sure the node owner is listed as an ad owner
  if (!db_result(db_query('SELECT oid FROM {ad_owners} WHERE uid = %d AND aid = %d', $node->uid, $node->nid))) {
    ad_owners_add($node->nid, $node->uid);
  }
 
  $header = array(
    array('data' => t('Username'), 'field' => 'uid'),
    array('data' => t('Options')),
  );
 
  drupal_set_title('owners');
 
  $sql = "SELECT uid FROM {ad_owners} WHERE aid = $node->nid";
  $sql .= tablesort_sql($header);
  $result = pager_query($sql, 25);
 
  $rows = array();
  while ($ad = db_fetch_object($result)) {
    $row = array();
    $user = user_load(array('uid' => $ad->uid));
    $row[] = $user->name;
    $options = array();
    // first option is 'permissions', plug-ins come afterwards
    $options[] = l(t('permissions'), "node/$node->nid/adowners/$user->uid/permissions");
    $options = array_merge($options, module_invoke_all('adowners', 'overview', $node->nid, $user->uid));
    // node owner has to remain an ad owner
    if ($ad->uid != $node->uid) {
      $options[] = l(t('remove'), "node/$node->nid/adowners/$user->uid/remove");
    }
    $options = implode(' | ', $options);
    $row[] = $options;
    $rows[] = $row;
  }
 
  $output = theme('table', $header, $rows);
  $output .= theme('pager', NULL, 25, 0);
 
  return $output;
}
 
/**
 * A simple form for adding new users as owners of ads.
 */
function ad_owners_add_form($node) {
  $form = array();
  drupal_set_title('Add owner');
 
  $form['aid'] = array(
    '#type' => 'value',
    '#value' => $node->nid,
  );
  $form['username'] = array(
    '#autocomplete_path' => 'user/autocomplete',
    '#description' => t('Enter the username of the user who should have ownership permissions on this advertisement.'),
    '#required' => TRUE, 
    '#type' => 'textfield',
    '#title' => t('Username'),
  );
  $form['save'] = array(
    '#type' => 'submit',
    '#value' => t('Add owner'),
  );
 
  return $form;
}
 
function ad_owners_add_form_validate($form_id, $form_values) {
  $owner = user_load(array('name' => $form_values['username']));
  if (!is_object($owner)) {
    form_set_error('username', t('The specified username %username does not exist.', array('%username' => $form_values['username'])));
  }
  else if (db_result(db_query('SELECT oid FROM {ad_owners} WHERE uid = %d AND aid = %d', $owner->uid, $form_values['aid']))) {
    form_set_error('username', t('The specified user %username is already an owner of this ad.', array('%username' => $form_values['username'])));
  }
  else if (!user_access('edit own advertisements', $owner) &&
           !user_access('administer advertisements', $owner)) {
    form_set_error('username', t('The specified user %username does not have <em>edit own advertisements</em> nor <em>administer advertisements</em> permissions.  The user must be !assigned to a !role with these privileges before you can add them as an ad owner.', array('%username' => $form_values['username'], '!assigned' => l(t('assigned'), "user/$owner->uid/edit"), '!role' => l(t('role'), 'admin/user/access'))));
  }
  module_invoke_all('adowners', 'validate', $owner, $form_values['aid']);
}
 
function ad_owners_add_form_submit($form_id, $form_values) {
  $owner = user_load(array('name' => $form_values['username']));
  if (!(ad_owners_add($form_values['aid'], $owner->uid, array('access statistics', 'access click history')))) {
    form_set_error('username', t('The user is already an owner of the ad.'));
  }
  else {
    drupal_set_message(t('The user %username has been added as an owner of this advertisement.', array('%username' => $form_values['username'])));
    drupal_goto('node/'. $form_values['aid'] ."/adowners/$owner->uid/permissions");
  }
}
 
function ad_is_owner($aid, $account = NULL) {
  global $user;
  if (is_null($account)) {
    $account = $user;
  }
  if (db_result(db_query('SELECT oid FROM {ad_owners} WHERE uid = %d AND aid = %d', $user->uid, $aid))) {
    return 1;
  }
  else {
    return 0;
  }
}
 
/**
 * Add an owner to an ad.
 */
function ad_owners_add($aid, $uid, $default = array('access statistics', 'access click history', 'manage status')) {
  $node = node_load($aid);
  if ($GLOBALS['db_type'] == 'pgsql') {
    db_query('START TRANSACTION;');
  }
  else {
    // MySQL, MySQLi
    db_query('LOCK TABLES {ad_owners} WRITE');
  }
 
  if (!db_result(db_query('SELECT oid FROM {ad_owners} WHERE uid = %d AND aid = %d', $uid, $aid))) {
    db_query('INSERT INTO {ad_owners} (aid, uid) VALUES(%d, %d)', $aid, $uid);
    $rc = db_affected_rows() ? 1 : 0;
 
    $permissions = array();
    foreach ($default as $permission) {
      if ($permission == ALL) {
        $permissions = module_invoke_all('adapi', 'permissions', $node);
        break;
      }
      else {
        $permissions[] = $permission;
      }
    }
 
    $oid = db_result(db_query("SELECT oid FROM {ad_owners} WHERE aid = %d and uid = %d", $aid, $uid));
    if ($GLOBALS['db_type'] == 'pgsql') {
      db_query('START TRANSACTION;');
    }
    else {
      // MySQL, MySQLi
      db_query('LOCK TABLES {ad_permissions} WRITE');
    }
    db_query('DELETE FROM {ad_permissions} WHERE oid = %d', $oid);
    db_query("INSERT INTO {ad_permissions} VALUES(%d, '%s')", $oid, implode('|,|', $permissions));
    module_invoke_all('adowners', 'add', $node, array('oid' => $oid, 'uid' => $uid, 'aid' => $aid));
  }
  if ($GLOBALS['db_type'] == 'pgsql') {
    db_query('COMMIT;');
  }
  else {
    // MySQL, MySQLi
    db_query('UNLOCK TABLES');
  }
  return $rc;
}
 
/**
 * Display a form with all available permissions and their status for the 
 * selected ad and ad owner.
 */
function ad_owner_permissions($aid, $uid) {
  drupal_set_title('Permissions');
 
  $oid = db_result(db_query("SELECT oid FROM {ad_owners} WHERE aid = %d and uid = %d", $aid, $uid));
  $granted = explode('|,|', db_result(db_query("SELECT permissions FROM {ad_permissions} WHERE oid = %d", $oid)));
 
  $form['header'] = array(
    '#type' => 'value',
    '#value' => array(t('permissions'), t('granted'))
  );
 
  $rows = array();
 
  $node = node_load($aid);
  $permissions = module_invoke_all('adapi', 'permissions', $node);
  foreach ($permissions as $permission) {
    $form['permission']["$permission"] = array(
      '#value' => t("$permission"),
    );
    $form['grant'][str_replace(' ', '_', "$permission")] = array(
      '#type' => 'checkbox',
      '#default_value' => in_array("$permission", $granted) ? 1 : 0,
    );
  }
 
  $form['oid'] = array(
    '#type' => 'hidden',
    '#value' => $oid,
  );
 
  $form['aid'] = array(
    '#type' => 'hidden',
    '#value' => $aid,
  );
 
  $form['uid'] = array(
    '#type' => 'hidden',
    '#value' => $uid,
  );
 
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
 
  return $form;
}
 
/**
 * Display ad owner permissions in a simple table.
 */
function theme_ad_owner_permissions($form) {
  $output = drupal_render($form['options']);
  foreach (element_children($form['permission']) as $key) {
    $row = array();
    $row[] = drupal_render($form['permission']["$key"]);
    $row[] = drupal_render($form['grant'][str_replace(' ', '_', "$key")]);
    $rows[] = $row;
  }
 
  $output = theme('table', $form['header']['#value'], $rows);
  $output .= drupal_render($form);
  return $output;
}
 
/**
 * Store the ad owner's updated permissions in the ad_permissions table.
 */
function ad_owner_permissions_submit($form_id, $form_values) {
  $permissions = module_invoke_all('adapi', 'permissions', array());
  $perms = array();
  foreach ($permissions as $permission) {
    if ($form_values[str_replace(' ', '_', "$permission")]) {
      $perms[] = $permission;
    }
  }
  if ($GLOBALS['db_type'] == 'pgsql') {
    db_query('START TRANSACTION;');
  }
  else {
    // MySQL, MySQLi
    db_query('LOCK TABLES {ad_permissions} WRITE');
  }
  db_query('DELETE FROM {ad_permissions} WHERE oid = %d', $form_values['oid']);
  db_query("INSERT INTO {ad_permissions} VALUES(%d, '%s')", $form_values['oid'], implode('|,|', $perms));
  if ($GLOBALS['db_type'] == 'pgsql') {
    db_query('COMMIT;');
  }
  else {
    // MySQL, MySQLi
    db_query('UNLOCK TABLES');
  }
  drupal_set_message(t('The permissions have been saved.'));
  return "node/$form_values[aid]/adowners";
}
 
/**
 * Determine whether the user has a given privilege.
 */
function ad_adaccess($aid, $string, $account = NULL) {
  global $user;
  static $permissions = array();
 
  if (is_null($account)) {
    $account = $user;
  }
 
  // User #1 has all privileges:
  if ($account->uid == 1) {
    return TRUE;
  }
 
  // If you have administer permissions, you have all permissions.
  if (user_access('administer advertisements', $account)) {
    return TRUE;
  }
 
  if (!isset($permissions[$aid][$account->uid])) {
    $oid = db_result(db_query("SELECT oid FROM {ad_owners} WHERE aid = %d and uid = %d", $aid, $account->uid));
    $permissions[$aid][$account->uid] = explode('|,|', db_result(db_query("SELECT permissions FROM {ad_permissions} WHERE oid = %d", $oid)));
  }
 
  return (in_array("$string", $permissions[$aid][$account->uid]));
}
 
/**
 * Create a unique host id for each ad owner, used when displaying ads remotely.
 */
function ad_host_id_create($uid) {
  $hostid = db_result(db_query('SELECT hostid FROM {ad_hosts} WHERE uid = %d', $uid));
  if (!$hostid) {
    $hostid = md5($uid . time());
    db_query("INSERT INTO {ad_hosts} (uid, hostid) VALUES (%d, '%s')", $uid, md5($uid . time()));
  }
 
  return $hostid;
}
 
/**
 * Build default ad administratoin page.
 */
function ad_admin_list() {
  _ad_check_install();
 
  $output = drupal_get_form('ad_filter_form');
 
  if ($_POST['operation'] == 'delete' && $_POST['ads']) {
    return drupal_get_form('ad_multiple_delete_confirm');
  }
  $output .= drupal_get_form('ad_admin_ads');
 
  return $output;
}
 
/**
 * Provide a filterable list of advertisements.
 */
function ad_admin_ads() {
  $filter = ad_build_filter_query();
  $result = pager_query('SELECT a.*, n.* FROM {ads} a INNER JOIN {node} n ON a.aid = n.nid '. $filter['join'] .' '. $filter['where'] .' ORDER BY n.changed DESC', 50, 0, NULL, $filter['args']);
 
  $form['options'] = array('#type' => 'fieldset',
    '#title' => t('Update options'),
    '#prefix' => '<div class="container-inline">',
    '#suffix' => '</div>',
  );
  $options = array();
  foreach (module_invoke_all('ad_operations') as $operation => $array) {
    $options[$operation] = $array['label'];
  }
  $form['options']['operation'] = array('#type' => 'select', '#options' => $options,  '#default_value' => 'approve');
  $form['options']['submit'] = array('#type' => 'submit', '#value' => t('Update'));
 
  $destination = drupal_get_destination();
  while ($ad = db_fetch_object($result)) {
    $ads[$ad->aid] = '';
    $form['title'][$ad->aid] = array('#value' => l($ad->title, 'node/'. $ad->aid));
    $form['group'][$ad->aid] = array('#value' => _ad_get_group($ad->aid));
    $form['adtype'][$ad->aid] = array('#value' => $ad->adtype);
    $form['adstatus'][$ad->aid] = array('#value' => $ad->adstatus);
    $form['operations'][$ad->aid] = array('#value' => l(t('edit'), 'node/'. $ad->aid .'/edit', array(), $destination));
  }
  $form['ads'] = array('#type' => 'checkboxes', '#options' => $ads);
  $form['pager'] = array('#value' => theme('pager', NULL, 50, 0));
  return $form;
}
 
/**
 * Implementation of hook_ad_operations().
 */
function ad_ad_operations() {
  $operations = array(
    'approved' => array(
      'label' => t('Mark as approved'),
      'callback' => 'ad_operations_callback',
      'callback arguments' => array('approved'),
    ),
    'active' => array(
      'label' => t('Mark as active'),
      'callback' => 'ad_operations_callback',
      'callback arguments' => array('active'),
    ),
    'expired' => array(
      'label' => t('Mark as expired'),
      'callback' => 'ad_operations_callback',
      'callback arguments' => array('expired'),
    ),
    'pending' => array(
      'label' => t('Mark as pending'),
      'callback' => 'ad_operations_callback',
      'callback arguments' => array('pending'),
    ),
    'offline' => array(
      'label' => t('Mark as offline'),
      'callback' => 'ad_operations_callback',
      'callback arguments' => array('offline'),
    ),
    'unpublished' => array(
      'label' => t('Mark as unpublished'),
      'callback' => 'ad_operations_callback',
      'callback arguments' => array('unpublished'),
    ),
    'denied' => array(
      'label' => t('Mark as denied'),
      'callback' => 'ad_operations_callback',
      'callback arguments' => array('denied'),
    ),
    'delete' => array(
      'label' => t('Delete'),
    ),
  );
  return $operations;
}
 
/**
 * Callback function for admin mass approving ads.
 * TODO: Update activated and expired when appropriate.
 * TODO: Publish/unpublish nodes when appropriate.
 */
function ad_operations_callback($ads, $action) {
  $placeholders = implode(',', array_fill(0, count($ads), '%d'));
  db_query("UPDATE {ads} SET adstatus = '". $action ."' WHERE aid IN(". $placeholders .')', $ads);
  foreach ($ads as $aid) {
    $node = node_load($aid);
    ad_owners_add($aid, $node->uid);
    ad_host_id_create($node->uid);
    ad_statistics_increment($aid, 'update');
    ad_statistics_increment($aid, $action);
    // Allow ad type module to act on nodeapi events.  The adapi hook provides 
    // access to additional variables not available in the nodeapi hook.
    if ($node->adtype) {
      // Don't use module_invoke, as in pre-PHP5 the changes to $node won't be
      // passed back.
      $function = "ad_$node->adtype" .'_adapi';
      if (function_exists($function)) {
        $function($op, $node);
      }
    }
    // Allow ad cache module to act on nodeapi events.
    $cache = variable_get('ad_cache', 'none');
    if ($cache != 'none') {
      $function = "ad_cache_$cache" .'_adcacheapi';
      if (function_exists($function)) {
drupal_set_message("function($function) action($action)");
        $function($action, $node);
      }
    }
  }
}
 
/**
 * Display a form to confirm whether to really delete the selected ads.
 */
function ad_multiple_delete_confirm() {
  $edit = $_POST;
 
  $form['ads'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
  // array_filter returns only elements with TRUE values
  foreach (array_filter($edit['ads']) as $aid => $value) {
    $title = db_result(db_query('SELECT title FROM {node} WHERE nid = %d', $aid));
    $form['ads'][$aid] = array('#type' => 'hidden', '#value' => $aid, '#prefix' => '<li>', '#suffix' => check_plain($title) ."</li>\n");
  }
  $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
 
  return confirm_form($form,
                      t('Are you sure you want to delete these ads?'),
                      'admin/content/ad', t('This action cannot be undone.'),
                      t('Delete all'), t('Cancel'));
}
 
/**
 * Perform the actual ad deletions.
 */
function ad_multiple_delete_confirm_submit($form_id, $form_values) {
  if ($form_values['confirm']) {
    foreach ($form_values['ads'] as $aid => $value) {
      node_delete($aid);
    }
    drupal_set_message(t('The ads have been deleted.'));
  }
  return 'admin/content/ad';
}
 
/**
 * Theme ad administration overview.
 */
function theme_ad_admin_ads($form) {
  // Overview table:
  $header = array(theme('table_select_header_cell'), t('Title'), t('Group'), t('Type'), t('Status'), t('Operations'));
 
  $output .= drupal_render($form['options']);
  if (isset($form['title']) && is_array($form['title'])) {
    foreach (element_children($form['title']) as $key) {
      $row = array();
      $row[] = drupal_render($form['ads'][$key]);
      $row[] = drupal_render($form['title'][$key]);
      $row[] = drupal_render($form['group'][$key]);
      $row[] = drupal_render($form['adtype'][$key]);
      $row[] = drupal_render($form['adstatus'][$key]);
      $row[] = drupal_render($form['operations'][$key]);
      $rows[] = $row;
    }
 
  }
  else  {
    $rows[] = array(array('data' => t('No ads available.'), 'colspan' => '6'));
  }
 
  $output .= theme('table', $header, $rows);
  if ($form['pager']['#value']) {
    $output .= drupal_render($form['pager']);
  }
 
  $output .= drupal_render($form);
 
  return $output;
}
 
/**
 * Must select an ad if performing an operation.
 */
function ad_admin_ads_validate($form_id, $form_values) {
  $ads = array_filter($form_values['ads']);
  if (count($ads) == 0) {
    form_set_error('', t('No ads selected.'));
  }
}
 
/**
 * Submit the ad administration update form.
 */
function ad_admin_ads_submit($form_id, $form_values) {
  $operations = module_invoke_all('ad_operations');
  $operation = $operations[$form_values['operation']];
  // Filter out unchecked nodes
  $ads = array_filter($form_values['ads']);
  if ($function = $operation['callback']) {
    // Add in callback arguments if present.
    if (isset($operation['callback arguments'])) {
      $args = array_merge(array($ads), $operation['callback arguments']);
    }
    else {
      $args = array($ads);
    }
    call_user_func_array($function, $args);
 
    cache_clear_all();
    drupal_set_message(t('The update has been performed.'));
  }
}
 
/**
 * Build query for ad administration filters based on session.
 */
function ad_build_filter_query() {
  $filters = ad_filters();
 
  // Build query
  $where = $args = array();
  $join = '';
  foreach ($_SESSION['ad_overview_filter'] as $index => $filter) {
    list($key, $value) = $filter;
    switch ($key) {
      case 'status':
        list($value, $key) = explode('-', $value, 2);
        $op = $key == 1 ? '=' : '!=';
        $where[] = "a.adstatus $op '%s'";
        break;
      case 'group':
        $table = "tn$index";
        $where[] = "$table.tid = %d";
        $join .= "INNER JOIN {term_node} $table ON n.nid = $table.nid ";
        break;
      case 'type':
        $where[] = "a.adtype = '%s'";
        $adtypes = module_invoke_all('adapi', 'type', array());
        $value = $adtypes[$value];
    }
    $args[] = $value;
  }
  $where = count($where) ? 'WHERE '. implode(' AND ', $where) : '';
 
  return array('where' => $where, 'join' => $join, 'args' => $args);
}
 
/**
 * Theme ad administration filter selector.
 */
function theme_ad_filters($form) {
  $output .= '<ul class="clear-block">';
  if (sizeof($form['current'])) {
    foreach (element_children($form['current']) as $key) {
      $output .= '<li>'. drupal_render($form['current'][$key]) .'</li>';
    }
  }
 
  $output .= '<li><dl class="multiselect">'. (sizeof($form['current']) ? '<dt><em>'. t('and') .'</em> '. t('where') .'</dt>' : '') .'<dd class="a">';
  foreach (element_children($form['filter']) as $key) {
    $output .= drupal_render($form['filter'][$key]);
  }
  $output .= '</dd>';
 
  $output .= '<dt>'. t('is') .'</dt><dd class="b">';
 
  foreach (element_children($form['status']) as $key) {
    $output .= drupal_render($form['status'][$key]);
  }
  $output .= '</dd>';
 
  $output .= '</dl>';
  $output .= '<div class="container-inline" id="ad-admin-buttons">'. drupal_render($form['buttons']) .'</div>';
  $output .= '</li></ul>';
 
  return $output;
}
 
/**
 * List ad administration filters that can be applied.
 */
function ad_filters() {
  $session = &$_SESSION['ad_overview_filter'];
  $session = is_array($session) ? $session : array();
  // Regular filters
  $options = array();
  $options = array('pending-1' => t('pending'), 'approved-1' => t('approved'), 'active-1' => t('active'), 'offline-1' => t('offline'), 'unpublished-1' => t('unpublished'), 'expired-1' => t('expired'), 'denied-1' => t('denied'), 'pending-0' => t('not pending'), 'approved-0' => t('not approved'), 'active-0' => t('not active'), 'offline-0' => t('not offline'), 'unpublished-0' => t('not unpublished'), 'expired-0' => t('not expired'), 'denied-0' => t('not denied'));
 
  $filters['status'] = array('title' => t('status'),
    'options' => $options);
  $filters['type'] = array('title' => t('type'), 'options' => module_invoke_all('adapi', 'type', array()));
  // The taxonomy filter
  if ($taxonomy = module_invoke('taxonomy', 'get_tree', _ad_get_vid())) {
    $options = array();
    // TODO: Add support for the default group.
    //$options[0] = t('default');
    foreach ($taxonomy as $term) {
      $options[$term->tid] = $term->name;
    }
    $filters['group'] = array('title' => t('group'), 'options' => $options);
  }
 
  return $filters;
}
 
/**
 * Return form for advertisement administration filters.
 */
function ad_filter_form() {
  $session = &$_SESSION['ad_overview_filter'];
  $session = is_array($session) ? $session : array();
  $filters = ad_filters();
 
  $i = 0;
  $form['filters'] = array('#type' => 'fieldset',
    '#title' => t('Show only ads where'),
    '#theme' => 'ad_filters',
  );
  foreach ($session as $filter) {
    list($type, $value) = $filter;
    if ($type == 'category') {
      // Load term name from DB rather than search and parse options array.
      $value = module_invoke('taxonomy', 'get_term', $value);
      $value = $value->name;
    }
    else if ($type == 'status') {
      $value = $filters['status']['options'][$value];
    }
    else {
      $value = $filters[$type]['options'][$value];
    }
    $string = ($i++ ? '<em>and</em> where <strong>%a</strong> is <strong>%b</strong>' : '<strong>%a</strong> is <strong>%b</strong>');
    $form['filters']['current'][] = array('#value' => t($string, array('%a' => $filters[$type]['title'] , '%b' => $value)));
    if ($type == 'type') {
      // Remove the type option if it is already being filtered on.
      unset($filters['type']);
    }
    else if ($type == 'group') {
      unset($filters['group']);
    }
    if ($type == 'status') {
      foreach ($session as $option) {
        if ($option[0] == 'status') {
          list($value, $key) = explode('-', $option[1], 2);
          if ($key) {
            // One postive key means we can't have any more.
            // Remove the status option if we're already filtering on a positive
            // key (ie, 'active', as an ad can't be 'active' and 'pending')
            unset($filters['status']);
          }
          else {
            // When a key is selected, remove it and its inverse as there's
            // no logic in selecting the same key multiple times, and selecting
            // two opposite keys will always return 0 results.
            $inverse = $key == 1 ? 0 : 1;
            unset($filters['status']['options'][$option[1]]);
            unset($filters['status']['options']["$value-$inverse"]);
          }
        }
      }
    }
  }
 
  foreach ($filters as $key => $filter) {
    $names[$key] = $filter['title'];
    $form['filters']['status'][$key] = array('#type' => 'select', '#options' => $filter['options']);
  }
 
  $form['filters']['filter'] = array('#type' => 'radios', '#options' => $names, '#default_value' => 'status');
  $form['filters']['buttons']['submit'] = array('#type' => 'submit', '#value' => (count($session) ? t('Refine') : t('Filter')));
  if (count($session)) {
    $form['filters']['buttons']['undo'] = array('#type' => 'submit', '#value' => t('Undo'));
    $form['filters']['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset'));
  }
 
  return $form;
}
 
/**
 * Theme ad administration filter form.
 */
function theme_ad_filter_form($form) {
  $output .= '<div id="ad-admin-filter">';
  $output .= drupal_render($form['filters']);
  $output .= '</div>';
  $output .= drupal_render($form);
  return $output;
}
 
/**
 * Process result from ad administration filter form.
 */
function ad_filter_form_submit($form_id, $form_values) {
  $filters = ad_filters();
  switch ($form_values['op']) {
    case t('Filter'):
    case t('Refine'):
      if (isset($form_values['filter'])) {
        $filter = $form_values['filter'];
 
        // Flatten the options array to accommodate hierarchical/nested options.
        $flat_options = form_options_flatten($filters[$filter]['options']);
 
        if (isset($flat_options[$form_values[$filter]])) {
          $_SESSION['ad_overview_filter'][] = array($filter, $form_values[$filter]);
        }
      }
      break;
    case t('Undo'):
      array_pop($_SESSION['ad_overview_filter']);
      break;
    case t('Reset'):
      $_SESSION['ad_overview_filter'] = array();
      break;
  }
}
 
/**
 *
 */
function ad_admin_statistics() {
  $groups = ad_groups_list(TRUE);
  foreach ($groups as $tid => $group) {
    if ($tid) {
      $ads = db_result(db_query("SELECT count(aid) FROM {ads} a JOIN {term_node} t ON a.aid = t.nid WHERE t.tid = %d AND adstatus = 'active'", $tid));
      $filter = "= $tid";
    }
    else {
      $ads = db_result(db_query("SELECT count(aid) FROM {ads} a LEFT JOIN {term_node} t ON a.aid = t.nid WHERE t.tid IS NULL AND adstatus = 'active'"));
      $filter = "IS NULL";
    }
    if (!$ads) {
      continue;
    }
 
    $form[$group->name] = array(
      '#type' => 'fieldset',
      '#title' => $group->name,
      '#collapsible' => TRUE,
    );
 
    // Get overall global statistics.
    $statistics['global']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND n.tid $filter"));
    $statistics['global']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND n.tid $filter"));
 
    // Get overall statistics for this year and last year.
    $this_year = date('Y000000');
    $last_year = date('Y') - 1 .'000000';
    $statistics['last_year']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date >= %d AND date <= %d AND n.tid $filter", $last_year, $this_year));
    $statistics['last_year']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date >= %d AND date <= %d AND n.tid $filter", $last_year, $this_year));
    $statistics['this_year']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date >= %d AND n.tid $filter", $this_year));
    $statistics['this_year']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date >= %d AND n.tid $filter", $this_year));
  
    // Get statistics for this month and last month.
    $this_month = date('Ym0000');
    $last_month = date('m') - 1;
    if ($last_month == 0) {
      $last_month = date('Y') - 1 .'120000';
    }
    else {
      $last_month = date('Y'). ($last_month < 10 ? '0' : '') . $last_month .'0000';
    }
    $statistics['last_month']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date >= %d AND date <= %d AND n.tid $filter", $last_month, $this_month));
    $statistics['last_month']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date >= %d AND date <= %d AND n.tid $filter", $last_month, $this_month));
    $statistics['this_month']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date >= %d AND n.tid $filter", $this_month));
    $statistics['this_month']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date >= %d AND n.tid $filter", $this_month));
  
    // Get statistics for this week.
    $this_week_start = date('Ymd00', time() - 60*60*24*6);
    $statistics['this_week']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date >= %d AND n.tid $filter", $this_week_start));
    $statistics['this_week']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date >= %d AND n.tid $filter", $this_week_start));
  
    // Get statistics for yesterday and today.
    $yesterday_start = date('Ymd00', time() - 60*60*24);
    $yesterday_end = date('Ymd24', time() - 60*60*24);
    $today_start = date('Ymd00', time());
    $statistics['yesterday']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date >= %d AND date <= %d AND n.tid $filter", $yesterday_start, $yesterday_end));
    $statistics['yesterday']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date >= %d AND date <= %d AND n.tid $filter", $yesterday_start, $yesterday_end));
    $statistics['today']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date >= %d AND n.tid $filter", $today_start));
    $statistics['today']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date >= %d AND n.tid $filter", $today_start));
  
    // Get statistics for this hour and the last hour.
    $last_hour = date('YmdH', time() - 60*60);
    $this_hour = date('YmdH', time());
    $statistics['last_hour']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date = %d AND n.tid $filter", $last_hour));
    $statistics['last_hour']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date = %d AND n.tid $filter", $last_hour));
    $statistics['this_hour']['views'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'view' AND date = %d AND n.tid $filter", $this_hour));
    $statistics['this_hour']['clicks'] = (int)db_result(db_query("SELECT SUM(s.count) FROM {ad_statistics} s LEFT JOIN {ads} a ON s.aid = a.aid LEFT JOIN {term_node} n ON a.aid = n.nid WHERE action = 'click' AND date = %d AND n.tid $filter", $this_hour));
 
    // TODO: Create this view and remove the && FALSE to enable this code.
    if (module_exists('views') && FALSE) {
      $form[$group->name]['statistics'] = array(
        '#type' => 'markup',
        '#value' => '<p>'. t('There %count in this group.', array('%count' => format_plural($ads, 'is '. l('1 active ad', "ad/$group->gid/group"), 'are '. l('%count active ads', "ad/$group->tid/group")))) .'</p>' . theme('ad_statistics_display', $statistics),
      );
    }
    else {
      $form[$group->name]['statistics'] = array(
        '#type' => 'markup',
        '#value' => '<p>'. t('There @count in this group.', array('@count' => format_plural($ads, 'is 1 active ad', 'are @count active ads'))) .'</p>' . theme('ad_statistics_display', $statistics),
      );
    }
  }
 
  if (count($form) == 0) {
    $form['header'] = array(
      '#type' => 'markup',
      '#value' => '<p>'. t('There are no active ads.') .'</p>',
    );
  }
 
  return $form;
}
 
/**
 * Display a form for the ad module settings.
 */
function ad_admin_configure_settings($edit = array()) {
  _ad_check_install();
 
  $edit = $_POST['edit'];
 
  $adserve = variable_get('adserve', '');
  $adserveinc = variable_get('adserveinc', '');
  $form['configuration'] = array(
    '#type' => 'fieldset',
    '#title' => t('Status'),
  );
  $form['configuration']['adserve'] = array(
    '#type' => 'markup',
    '#value' => t('Using detected adserve scripts: %adserve, %adserveinc', array('%adserve' => ($adserve ? $adserve : t('not found')), '%adserveinc' => ($adserveinc ? $adserveinc : t('not found')))),
  );
 
  $form['general'] = array(
    '#type' => 'fieldset', 
    '#title' => t('General'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );
 
  // TODO: This needs a per-group over-ride, in case some groups are IFrames,
  // while others are JavaScript, etc.
  $form['general']['ad_link_target'] = array(
    '#type' => 'radios',
    '#title' => t('Click-through target'),
    '#options' => array(
      '_self' => t('same browser window and frame'), 
      '_blank' => t('new browser window'), 
      '_parent' => t('parent frame'), 
      '_top' => t('same browser window, removing all frames'),
    ),
    '#default_value' => variable_get('ad_link_target', '_self'),
    '#description' => t('Select an option above to configure what happens when an ad is clicked.  These options set the <em>a target</em>, and are <em>_self</em>, <em>_blank</em>, <em>_parent</em> and <em>_top</em> respectively.'),
  );
 
  $form['general']['ad_link_nofollow'] = array(
    '#type' => 'checkbox',
    '#title' => t('nofollow'),
    '#default_value' => variable_get('ad_link_nofollow', 0),
    '#description' => t('If enabled, %tag will be added to advertisement links generated by this module.', array('%tag' => t('rel="nofollow"'))),
  );
 
  // Provide hook for ad_display_TYPE modules to set display TYPE.
  $display_options = array_merge(array('javascript' => t('JavaScript'), 'iframe' => t('IFrame'), 'raw' => t('Raw')), module_invoke_all('displayapi', 'display_method'), array());
 
  // Provide hook for ad_display_TYPE modules to define inline description.
  $description = t('This setting configures the default method for displaying advertisements on your website.  It is possible to override this setting when making direct calls to ad(), as described in the documentation.  Using the JavaScript and IFrame display methods allows you to display random ads and track views even on cached pages.  When using the Raw display method together with Drupal\'s page cache, view statistics will be properly tracked but advertisements will only change when the page cache is updated.');
  $return = module_invoke_all('displayapi', 'display_description', array());
  foreach ($return as $describe) {
    $description .= ' '. $describe;
  }
 
  $form['general']['ad_display'] = array(
    '#type' => 'radios', 
    '#title' => t('Display type'), 
    '#default_value' => variable_get('ad_display', 'javascript'), 
    '#options' => $display_options,
    '#description' => $description,
  );
 
  $form['general']['ad_validate_url'] = array(
    '#type' => 'checkbox',
    '#title' => t('Validate URLs'), 
    '#default_value' => variable_get('ad_validate_url', 1), 
    '#description' => t('If enabled, any destination URLs entered in ads will be required to be complete URLs (including http:// or https:// at the beginning).  If you wish to include internal urls, you will need to disable this option.'),
  );
 
  $form['iframe'] = array(
    '#type' => 'fieldset', 
    '#title' => t('IFrame'),
    '#collapsible' => TRUE,
    '#collapsed' => variable_get('ad_display', 'javascript') == 'iframe' ? FALSE : TRUE
  );
  $form['iframe']['ad_iframe_frameborder'] = array(
    '#type' => 'checkbox', 
    '#title' => t('Frameborder'),
    '#default_value' => variable_get('ad_iframe_frameborder', 0), 
    '#description' => t('If enabled, IFrames used for displaying ads will have a frameborder.'),
  );
  $form['iframe']['ad_iframe_scroll'] = array(
    '#type' => 'radios', 
    '#title' => t('Scrolling'), 
    '#default_value' => variable_get('ad_iframe_scroll', 'auto'), 
    '#options' => array('auto' => 'auto', 'on' => 'on', 'off' => 'off'),
    '#description' => t('Define whether or not scroll bars should be enabled for the ad IFrame.'),
  );
  $form['iframe']['ad_iframe_width'] = array(
    '#type' => 'textfield',
    '#title' => t('Width'),
    '#default_value' => variable_get('ad_iframe_width', ''), 
    '#maxlength' => 8,
    '#size' => 5,
    '#required' => FALSE,
    '#description' => t('The default width for advertisement IFrames'),
  );
  $form['iframe']['ad_iframe_height'] = array(
    '#type' => 'textfield',
    '#title' => t('Height'),
    '#default_value' => variable_get('ad_iframe_height', ''), 
    '#maxlength' => 8,
    '#size' => 5,
    '#required' => FALSE,
    '#description' => t('The default height for advertisement IFrames'),
  );
 
  $form['cache'] = array(
    '#type' => 'fieldset', 
    '#title' => t('Cache'),
    '#collapsible' => TRUE,
    '#collapsed' => variable_get('ad_cache', 'none') == 'none' ? TRUE : FALSE,
  );
 
  // Provide hook for ad_cache_TYPE modules to set cache TYPE.
  $cache_options = array_merge(array('none' => t('None')), module_invoke_all('adcacheapi', 'method', array()));
 
  // Provide hook for ad_cache_TYPE modules to define inline description.
  $description = t('A cache can be used to efficiently track how many times advertisements are displayed and clicked.');
  $return = module_invoke_all('adcacheapi', 'description', array());
  foreach ($return as $describe) {
    $description .= ' '. $describe;
  }
 
  $form['cache']['ad_cache'] = array(
    '#type' => 'radios', 
    '#title' => t('Type'), 
    '#default_value' => variable_get('ad_cache', 'none'), 
    '#options' => $cache_options,
    '#description' => $description,
  );
 
  // Provide hook for ad_cache_TYPE modules to add inline settings.
  $form['cache'] = array_merge($form['cache'], module_invoke_all('adcacheapi', 'settings', $edit));
 
  $form['save'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
 
  return $form;
}
 
/**
 * Validate form settings, calling attention to any illogical configurations.
 */
function ad_admin_configure_settings_validate($form_id, $form_values) {
  if ($form_values['ad_link_target'] == '_self' && 
      $form_values['ad_display'] == 'iframe') {
    // We don't consider this an error, as this could be exactly what the
    // administrator is trying to do.  But as for most people it is likely
    // to be a misconfiguration, display a helpful warning...
    drupal_set_message('You have configured your advertisements to be displayed in iframes, and you have configured your click-through target as "same browser window and frame".  This is an unusual configuration, as when you click your advertisements only the IFrame will be redirected.  Be sure that this is actually what you are trying to do.');
  }
}
 
/**
 * Save updated values from settings form.
 */
function ad_admin_configure_settings_submit($form_id, $form_values) {
  variable_set('ad_link_target', $form_values['ad_link_target']);
  variable_set('ad_link_nofollow', $form_values['ad_link_nofollow']);
  variable_set('ad_cache', $form_values['ad_cache']);
  variable_set('ad_display', $form_values['ad_display']);
  variable_set('ad_validate_url', $form_values['ad_validate_url']);
  variable_set('ad_iframe_frameborder', $form_values['ad_iframe_frameborder']);
  variable_set('ad_iframe_scroll', $form_values['ad_iframe_scroll']);
  variable_set('ad_iframe_width', $form_values['ad_iframe_width']);
  variable_set('ad_iframe_height', $form_values['ad_iframe_height']);
  if (($cache = variable_get('ad_cache', 'none')) != 'none') {
    // Allow external cache types to store their settings
    module_invoke('ad_cache_'. $cache, 'adcacheapi', 'settings_submit', $form_values);
  }
/*
 // TODO: Write an external display module and implement this.
  $display = variable_get('ad_display', 'javascript');
  if ($display != 'javascript' && $display != 'raw') {
    // Allow external display types to store their settings
    module_invoke('ad_cache_'. $cache, 'adcacheapi', 'settings_submit', $form_values);
  }
*/
}
 
/**
 * Return an array of all groups, or a specific group.
 *
 * @param $tid
 *  If set to an integer >0, will only return group info about that specific
 *   group.
 * @object
 *  If FALSE, will return only name of group(s).  If TRUE, will return full
 *  group object including ->name, ->description, and ->tid.
 */
function ad_groups_list($object = FALSE, $tid = NULL) {
  static $groups = array();
  static $names = array();
 
  // Return the full group object(s).
  if ($object) {
    if (empty($groups)) {
      $tids = taxonomy_get_tree(_ad_get_vid());
      foreach ($tids as $group) {
        $groups[$group->tid]->name = "$group->name";
        $groups[$group->tid]->description = "$group->description";
        $groups[$group->tid]->tid = $group->tid;
      }
      // Hard coded "default" group with tid of 0.
      $groups[0]->name = t('default');
      $groups[0]->description = t('The default ad group is comprised of all ads not assigned to any other ad group.');
      $groups[0]->tid = 0;
    }
    // Return a specific group object.
    if ((int)$tid) {
      return $groups[$tid];
    }
    // Return an array of all group objects.
    else {
      return $groups;
    }
  }
  // Return only the group name(s).
  else {
    if (empty($names)) {
      $tids = taxonomy_get_tree(_ad_get_vid());
      foreach ($tids as $group) {
        $names[$group->tid] = "$group->name";
      }
      // Hard coded "default" group with tid of 0.
      $names[0] = t('default');
    }
    // Return a specific group name.
    if ((int)$tid) {
      return $names[$tid];
    }
    // Return an array of all group names.
    else {
      return $names;
    }
  }
}
 
function ad_admin_groups_list() {
  _ad_check_install();
 
  $header = array(
      array('data' => t('Name'), 'field' => 'name'),
      array('data' => t('Description'), 'field' => 'description'),
      array('data' => t('Options')),
    );
 
  $groups = taxonomy_get_tree(_ad_get_vid());
 
  if ($groups != array()) {
    foreach ($groups as $group) {
      $row = array();
      $row[] = $group->name;
      $row[] = $group->description;
      $row[] = l(t('edit'), "admin/content/ad/groups/$group->tid/edit");
      $rows[] = $row;
    }
  }
  else {
    $rows[] = array(array('data' => t('No groups have been created.'), 'colspan' => 3));
  }
 
  $output = theme('table', $header, $rows);
  $output .= theme('pager', NULL, 15, 0);
 
  return $output;
}
 
function ad_owner_remove($aid, $uid) {
  $form['aid'] = array(
    '#type' => 'value',
    '#value' => $aid,
  );
  $form['uid'] = array(
    '#type' => 'value',
    '#value' => $uid,
  );
  $owner = user_load(array('uid' => $uid));
  return confirm_form($form,
    t('Are you sure you want to remove user %name as an owner of this advertisement?', array('%name' => $owner->name)),
    "node/$aid/adowners",
    t('This action cannot be undone.'),
    t('Remove'),
    t('Cancel')
  );
}
 
/**
 * Don't allow the removal of the primary owner of the advertisement.
 */
function ad_owner_remove_validate($form_id, $form_values) {
  $node = node_load($form_values['aid']);
  if ($node->uid == $form_values['uid']) {
    $owner = user_load(array('uid' => $form_values['uid']));
    drupal_set_message(t('%name is the primary owner of this advertisement.  You cannot remove the primary owner.', array('%name' => $owner->name)), 'error');
    drupal_goto('node/'. $form_values['aid'] .'/adowners');
  }
}
 
/**
 * Remove the ad owner, and all associated permissions.
 */
function ad_owner_remove_submit($form_id, $form_values) {
  $oid = db_result(db_query('SELECT oid FROM {ad_owners} WHERE aid = %d AND uid = %d', $form_values['aid'], $form_values['uid']));
  db_query('DELETE FROM {ad_owners} WHERE oid = %d', $oid);
  db_query('DELETE FROM {ad_permissions} WHERE oid = %d', $oid);
  $owner = user_load(array('uid' => $form_values['uid']));
  module_invoke_all('adowners', 'remove', $oid, $owner);
  drupal_set_message(t('The ad owner %name has been removed.', array('%name' => $owner->name)));
  drupal_goto('node/'. $form_values['aid'] .'/adowners');
}
 
/**
 * Implement ad notify api _hook.
 */
function ad_adnotifyapi($op, $arg1 = NULL, $arg2 = NULL) {
  switch ($op) {
    // Make the following events available for notification.
    case 'register':
      return array(
        '-expired' => t('Email @when before the advertisement will expire.'),
        'expired' => t('Email @when after the advertisement is expired.'),
        '-active' => t('Email @when before the advertisement will be activated (if scheduled).'),
        'active' => t('Email @when after the advertisement is activated.'),
        'click' => t('Email @when after the advertisement is clicked.'),
        'approved' => t('Email @when after the advertisement is approved.'),
        'denied' => t('Email @when after the advertisement is denied.'),
      );
      break;
    case '-expired':
      $node = node_load($arg1->aid);
      if (isset($node->autoexpire) && $node->autoexpire) {
        if ((time() + $arg1->delay >= $node->autoexpire) &&
            ($arg1->sent + $arg1->delay < $node->autoexpire)) {
          return array('-expired' => 1);
        }
      }
      break;
    case '-active':
      $node = node_load($arg1->aid);
      if (isset($node->autoactivate) && $node->autoactivate) {
        if ((time() + $arg1->delay >= $node->autoactivate) &&
            ($arg1->sent + $arg1->delay < $node->autoactivate)) {
          return array('-active' => 1);
        }
      }
      break;
    case 'mail_text':
      switch ($arg1) {
        case 'expired':
          return array(
            'subject' => t('[%sitename ad] %event notification'),
            '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"),
          );
        case '-expired':
          return array(
            'subject' => t('[%sitename ad] expiration notification'),
            '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"),
          );
        case 'active':
          return array(
            'subject' => t('[%sitename ad] %event notification'),
            '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"),
          );
        case '-active':
          return array(
            'subject' => t('[%sitename ad] activation notification'),
            '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"),
          );
        case 'click':
          return array(
            'subject' => t('[%sitename ad] %event notification'),
            '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"),
          );
        case 'approved':
          return array(
            'subject' => t('[%sitename ad] %event notification'),
            '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"),
          );
        case 'denied':
          return array(
            'subject' => t('[%sitename ad] %event notification'),
            '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"),
          );
      }
      break;
  }
}
 
/****/
 
function _ad_check_install() {
  // Verify serve.php exists and is readable.
  $adserve = variable_get('adserve', '');
  $adserveinc = variable_get('adserveinc', '');
  if (!file_exists($adserve)) {
    // The serve.php file should be in the same directory as the ad.module.
    $adserve = drupal_get_path('module', 'ad') .'/serve.php';
    variable_set('adserve', $adserve);
  }
  if (!is_readable($adserve)) {
    variable_set('adserve', '');
    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');
  }
  if (!file_exists($adserveinc)) {
    // The adserve.inc file should be in the same directory as the ad.module.
    $adserveinc = drupal_get_path('module', 'ad') .'/adserve.inc';
    variable_set('adserveinc', $adserveinc);
  }
  if (!is_readable($adserveinc)) {
    variable_set('adserveinc', '');
    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');
  }
 
  // Validate vid in vocabulary table.
  $vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE module = 'ad'"));
  if ($vid != variable_get('ad_group_vid', '')) {
    drupal_set_message(t('Invalid vocabulary defined for advertisements, attempting to auto-fix.'), 'error');
    if ($vid) {
      db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d OR type = 'ad'", variable_get('ad_group_vid'));
      variable_set('ad_group_vid_restore', variable_get('ad_group_vid', ''));
    }
    variable_del('ad_group_vid');
  }
  else {
    // Validate vid in vocabulary_node_types table.
    $result = db_query("SELECT vid FROM {vocabulary_node_types} WHERE type = 'ad'");
    $found = FALSE;
    while ($vocab = db_fetch_object($result)) {
      if ($vocab->vid == variable_get('ad_group_vid', '')) {
        $found = TRUE;
      }
    }
    if (!$found) {
      drupal_set_message(t('Missing vocabulary node type for advertisements, attempting to auto-fix.'), 'error');
      db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d OR type = 'ad'", variable_get('ad_group_vid'));
      db_query("DELETE FROM {vocabulary} WHERE vid = %d", variable_get('ad_group_vid'));
      variable_set('ad_group_vid_restore', variable_get('ad_group_vid', ''));
      variable_del('ad_group_vid');
    }
  }
 
  _ad_get_vid();
  // Preserve old ad groups, if any.
  if (($old = variable_get('ad_group_vid_restore', '')) && 
       $vid = variable_get('ad_group_vid', '')) {
    drupal_set_message(t('Restoring orphaned ad group configuration.'));
    db_query('UPDATE {term_data} SET vid = %d WHERE vid = %d', $vid, $old);
    variable_set('ad_group_vid_restore', '');
  }
 
  $result = db_query("SELECT rid FROM {permission} WHERE perm LIKE '%%show advertisements%%'");
  if (!db_num_rows($result)) {
    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/access'))));
  }
 
  module_invoke_all('adapi', 'check_install', array());
}
 
/**
 * Creates a vocabulary for use by ad groups if not already created.
 */
function _ad_get_vid() {
  $vid = variable_get('ad_group_vid', '');
  if (empty($vid)) {
    // No vid stored in the variables table, check if one even exists.
    $vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE module = '%s'", 'ad'));
    if (!$vid) {
      // No vid, so we create one.
      $edit = array('name' => 'Ad groups', 'multiple' => 1, 'required' => 0, 'hierarchy' => 0, 'relations' => 0, 'module' => 'ad', 'nodes' => array('ad' => 1));
      taxonomy_save_vocabulary($edit);
      $vid = $edit['vid'];
    }
    // Save the vid for next time.
    variable_set('ad_group_vid', $vid);
  }
  return $vid;
}
 
/**
 * Returns a form for adding an ad group.
 */
function ad_admin_group_form($group = array()) {
  if ($_POST['op'] == t('Delete') || $_POST['edit']['confirm']) {
    drupal_goto('admin/content/ad/groups/'. $group['tid'] .'/delete');
  }
 
  $form['name'] = array(
    '#type' => 'textfield',
    '#title' => t('Group name'),
    '#default_value' => $group['name'],
    '#maxlength' => 64,
    '#required' => TRUE,
    '#description' => t('Specify a name for the ad group.')
  );
 
  $form['description'] = array(
    '#type' => 'textarea',
    '#title' => t('Description'),
    '#default_value' => $group['description'],
    '#required' => TRUE,
    '#description' => t('Describe this ad group.')
  );
    
  $form['parent']['#tree'] = FALSE;
 
  $form['weight'] = array(
    '#type' => 'weight',
    '#title' => t('Weight'),
    '#default_value' => $group['weight'],
    '#description' => t('When listing ad groups, those with lighter (smaller) weights get listed before ad groups with heavier (larger) weights.  Ad groups with equal weights are sorted alphabetically.')
  );
 
  $form['vid'] = array(
    '#type' => 'hidden',
    '#value' => _ad_get_vid());
 
  $form['submit'] = array(
    '#type' => 'submit', 
    '#value' => t('Submit'));
 
  if ($group['tid']) {
    $form['delete'] = array(
      '#type' => 'submit', 
      '#value' => t('Delete'));
    $form['tid'] = array(
      '#type' => 'value', 
      '#value' => $group['tid']);
  }
 
  return $form;
}
 
/**
 * Save a newly created ad group.
 */
function ad_admin_group_form_submit($form_id, $form_values) {
  $status = taxonomy_save_term($form_values);
  switch ($status) {
    case SAVED_NEW:
      $groups = variable_get('ad_groups', array());
      $groups[] = $form_values['tid'];
      variable_set('ad_groups', $groups);
      drupal_set_message(t('Created new ad group %term.', array('%term' => $form_values['name'])));
      break;
    case SAVED_UPDATED:
      drupal_set_message(t('The ad group %term has been updated.', array('%term' => $form_values['name'])));
  }
  return 'admin/content/ad/groups';
}
 
/**
 * Returns a confirmation page when deleting an ad group and all of its ads.
 */
function ad_confirm_group_delete($term) {
  $form['tid'] = array('#type' => 'value', '#value' => $term['tid']);
  $form['name'] = array('#type' => 'value', '#value' => $term['name']);
 
  return confirm_form(
    $form,
    t('Are you sure you want to delete the ad group %name?', array('%name' => $term['name'])), 
    'admin/content/ad/group', 
    t('Ads that were within this group will not be deleted.  This action cannot be undone.'), 
    t('Delete'), 
    t('Cancel'));
}
 
/**
 * Delete ad group.
 */
function ad_confirm_group_delete_submit($form_id, $form_values) {
  taxonomy_del_term($form_values['tid']);
  drupal_set_message(t('The ad group %term has been deleted.', array('%term' => $form_values['name'])));
  watchdog('ad', t('mailarchive: deleted %term ad group.', array('%term' => $form_values['name'])));
 
  return 'admin/content/ad/groups';
}
 
/**
 * Builds the necessary HTML to display an image-based view counter.
 */
function ad_display_image($ad, $css = TRUE) {
  global $base_url;
  $adserve = variable_get('adserve', '');
  $cache = variable_get('ad_cache', 'none');
  $variables = "?o=image";
  if (is_object($ad)) {
    $aid = $ad->aid;
  }
  else {
    /**
     * No ad is specified, so we're just tracking traffic.
     */
    $aid = 0;
  }
  $variables .= "&amp;a=$aid";
  if ($cache != 'none') {
    $variables .= '&amp;c='. $cache . module_invoke('ad_cache_'. $cache, 'adcacheapi', 'display_variables', array());
  }
  $output = '<img src="'. url("$base_url/$adserve$variables") .'" height="0" width="0" alt="view counter" />';
  if ($css) {
    return '<div class="ad-image-counter">'. $output .'</div>';
  }
  else {
    return $output;
  }
}
 
/**
 * Retrieve the group name from the nid.
 */
function _ad_get_group($nid) {
  static $groups = array();
 
  if (!isset($groups[$nid])) {
    $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());
    while ($term = db_fetch_object($result)) {
      $terms[] = $term->name;
    }
    if (!empty($terms)) {
      $groups[$nid] = implode(', ', $terms);
    }
    else {
      $groups[$nid] = t('default');
    }
  }
 
  return $groups[$nid];
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of gwkg
gwkg
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of mysmp

ASKER

Nice, I got all that stuff implemented.  Now I see the ad in IE but its not wrapping.  Firefox remains working correctly.  At least we got it to show in IE....here is the code that I have in the AD module:

<div style = float:left>
<script type="text/javascript">
  GA_googleFillSlot("ino_300_250");
</script>
</div>

Can you tell me what i need to do to fix that so it wraps in IE?
give the floating <div> a width
at least the 300px width of the ad
Avatar of mysmp

ASKER

Hi, the ad is 250 by 250.  

Here is what I have:  

<div style = float: left; width: 252px;>
<script type="text/javascript">
  GA_googleFillSlot("ino_300_250");
</script>
</div>

This didnt work
Avatar of mysmp

ASKER

Hi, anyone have any suggestions to why this wont work in IE?  I stand corrected, the ad is currently 300 by 250...I read something about clearing a float?  I have no idea what this means but thought I would put it out here if it sparks anything....
It should work.  You can't float blocks without a width, but you added the width.
You should repost your new question in the CSS and Javascript Zones.
Your original question appears to have been answered by gwkg, as you acknowledge in comment 23470309, but because you haven't awarded points other experts are still being directed here.  Please award points.