@i", "* ", $body);
$body = strip_tags($body);
$body = decode_entities($body);
$body = wordwrap($body, 72);
}
else {
$body = decode_entities($body);
}
return $body;
}
/**
* Implementation of hook_mail().
*/
function og_mail($key, &$message, $params) {
$language = $message['language'];
$message['subject'] .= _og_mail_text($key .'_subject', $language, $params);
$message['body'][] = _og_mail_text($key .'_body', $language, $params);
}
/**
* Define all OG email bodies
* Modelled after user.module
*/
function _og_mail_text($messageid, $language = NULL, $variables = array()) {
$langcode = isset($language) ? $language->language : NULL;
// Check if an admin setting overrides the default string.
if ($admin_setting = variable_get($messageid, FALSE)) {
return strtr($admin_setting, $variables);
}
// No override, return with default strings.
else {
switch ($messageid) {
case 'new_node_subject':
return t("@group: '@title' at @site", $variables, $langcode);
case 'new_node_body':
return t("@type '@subject' by @username\n\n@node_teaser\n\n!read_more: !content_url\nPost reply: !reply_url\n\n--\nYou are subscribed from the group '@group' at @site.\nTo manage your subscription, visit !group_url", $variables, $langcode);
case 'admin_email_subject':
return $variables['@subject'];
case 'admin_email_body':
return t("@body\n\n--\nThis message was sent by an administrator in the '@group' group at @site. To visit this group, browse to !url_group. To unsubscribe from this group, visit !url_unsubscribe", $variables, $langcode);
case 'approve_user_subject':
return t("Membership request approved for '@title'", $variables, $langcode);
case 'approve_user_body':
return t("You may now post messages in this group located at !group_url", $variables, $langcode);
case 'deny_user_subject':
return t("Membership request denied for '@title'", $variables, $langcode);
case 'deny_user_body':
return t("Sorry, your membership request was denied.", $variables, $langcode);
case 'invite_user_subject':
return t("Invitation to join the group '@group' at @site", $variables, $langcode);
case 'invite_user_body':
return t("Hi. I'm a member of '@group' and I welcome you to join this group as well. Please see the link and message below.\n\n@group\n@description\nJoin: !group_url\n@body", $variables, $langcode);
case 'request_user_subject':
return t("Membership request for '@group' from '@username'", $variables, $langcode);
case 'request_user_body':
return t("To instantly approve this request, visit !approve_url.\nYou may deny this request or manage members at !group_url. \n\nPersonal message from @username:\n------------------\n\n@request", $variables, $langcode);
case 'new_admin_subject':
return t("You are now an administrator for the group '@group'", $variables, $langcode);
case 'new_admin_body':
return t("@username, you are now an administrator for the group '@group'.\n\nYou can administer this group by logging in here:\n !group_url", $variables, $langcode);
}
}
}
// Helper function for queries that need all group types.
function og_get_sql_args() {
if ($types = og_get_types('group')) {
$in = 'IN ('. db_placeholders($types, "varchar"). ')';
}
else {
$in = 'IS NULL';
}
return array($types, $in);
}
function og_user($op, $edit, &$account, $category = NULL) {
global $user;
switch ($op) {
case 'register':
$options = array();
list($types, $in) = og_get_sql_args();
// If groups are passed on querystring, just use them.
if (isset($_REQUEST['gids']) && $gids = $_REQUEST['gids']) {
$default_value = $gids;
foreach ($gids as $gid) {
$nids[] = (int)$gid;
}
$in_nids = db_placeholders($nids);
$sql = "SELECT n.nid, n.title, o.* FROM {node} n INNER JOIN {og} o ON n.nid = o.nid WHERE n.type $in AND n.status = 1 AND n.nid IN ($in_nids) ORDER BY n.title";
$result = db_query(db_rewrite_sql($sql), array_merge($types, $nids));
}
else {
$default_value = array();
// perhaps this should be a View
$result = db_query(db_rewrite_sql("SELECT n.nid, n.title, o.* FROM {node} n INNER JOIN {og} o ON n.nid = o.nid WHERE n.type $in AND n.status = 1 AND o.register = 1 ORDER BY n.title"), $types);
}
while ($group = db_fetch_object($result)) {
$options[$group->nid] = ''. t('Join %name.', array('%name' => $group->title)). "\n";
if ($group->selective) {
$options[$group->nid] .= ' '. t('(approval needed)');
}
}
if (count($options)) {
$form['og_register'] = array('#type' => 'fieldset', '#title' => t('Groups'));
$form['og_register']['og_register'] = array(
'#type' => 'checkboxes',
'#options' => $options,
'#default_value' => $default_value,
);
}
return $form;
case 'form':
if ($category == 'account' && !empty($account->og_groups)) {
$form['og_settings'] = array(
'#type' => 'fieldset',
'#title' => t('Organic groups settings'),
'#collapsible' => TRUE,
'#weight' => 4);
$options = array(OG_NOTIFICATION_NEVER => t('Never send email notifications. Useful when tracking activity via RSS feed instead.'),
OG_NOTIFICATION_ALWAYS => t('Always send email notifications'),
OG_NOTIFICATION_SELECTIVE => t("Selectively send email notification based on the checkbox for each of my group's My Membership page."),
);
$form['og_settings']['og_email'] = array(
'#type' => 'radios',
'#title' => t('Email notifications'),
'#options' => $options,
'#default_value' => isset($account->og_email) ? $account->og_email : variable_get('og_notification', 2),
'#description' => t('When posts are submitted into your groups, you may be notified via email.'),
);
return $form;
}
break;
case 'insert':
if (is_array($edit['og_register'])) {
foreach (array_keys(array_filter($edit['og_register'])) as $gid) {
$return = og_subscribe_user($gid, $account);
if (!empty($return['message'])) {
drupal_set_message($return['message']);
}
}
}
$sql = 'INSERT INTO {og_uid_global} (uid, og_email) VALUES (%d, %d)';
db_query($sql, $account->uid, variable_get('og_notification', OG_NOTIFICATION_ALWAYS));
$account->og_email = NULL;
break;
case 'update':
if (isset($edit['og_email'])) {
$sql = 'UPDATE {og_uid_global} SET og_email=%d WHERE uid=%d';
db_query($sql, $edit['og_email'], $account->uid);
$account->og_email = NULL;
}
break;
case 'delete':
// User delete doesn't exist, but it should and will one day. See http://drupal.org/node/8
$sql = 'DELETE FROM {og_uid_global} WHERE uid=%d';
db_query($sql, $account->uid);
$sql = 'DELETE FROM {og_uid} WHERE uid=%d';
db_query($sql, $account->uid);
break;
case 'load':
$account->og_groups = og_get_subscriptions($account->uid);
$result = db_query_range("SELECT og_email FROM {og_uid_global} WHERE uid = %d", $account->uid, 0, 1);
if ($row = db_fetch_object($result)) {
$account->og_email = $row->og_email;
}
break;
case 'view':
if ($account->og_groups) {
foreach ($account->og_groups as $key => $val) {
$links[$key] = l($val['title'], "node/$key") . theme('og_format_subscriber_status', $val);
}
$account->content['summary']['groups'] = array(
'#type' => 'item',
'#title' => t('Groups'),
'#value' => theme('item_list', $links),
// Not working in 6
// '#theme' => 'item_list',
'#attributes' => array('class' => 'og_groups'),
// Only show list of groups to self and admins. TOOD: Make this configurable or doable via Views.
'#access' => $account->uid == $user->uid || user_access('administer organic groups'),
);
}
break;
}
}
function og_save_ancestry($node) {
if (og_is_group_post_type($node->type)) {
$sql = "DELETE FROM {og_ancestry} WHERE nid = %d";
db_query($sql, $node->nid);
if (isset($node->og_groups)) {
$node->og_groups = array_unique($node->og_groups);
foreach ($node->og_groups as $gid) {
$sql = "INSERT INTO {og_ancestry} (nid, group_nid, is_public) VALUES (%d, %d, %d)";
db_query($sql, $node->nid, $gid, $node->og_public);
}
}
}
}
/**
* An implementation of hook_node_type. Automatically update admin preferences when node type is renamed or removed.
*/
function og_node_type($op, $info) {
switch ($op) {
case 'delete':
variable_del('og_content_type_usage_'. $info->type);
break;
case 'update':
$usage = variable_get('og_content_type_usage_'. $info->type, 'omitted');
variable_set('og_content_type_usage_'. $info->type, $usage);
variable_del('og_content_type_usage_'. $info->old_type);
}
}
function og_types_map() {
$usages = array(
'group' => t('Group node'),
'omitted' => t('May not be posted into a group.'),
'group_post_standard_mail' => t('Standard group post (typically only author may edit). Sends email notifications.'),
'group_post_standard_nomail' => t('Standard group post (typically only author may edit). No email notification.'),
);
if (module_exists('og_access')) {
$usages['group_post_wiki_mail'] = t('Wiki group post (any group member may edit). Sends email notifications.');
$usages['group_post_wiki_nomail'] = t('Wiki group post (any group member may edit). No email notification.');
}
return $usages;
}
// Return all content types which meet a specified usage.
function og_get_types($usage) {
$types = node_get_types();
foreach ($types as $type) {
if ($usage == 'group_post') {
if (!og_is_omitted_type($type->type) && !og_is_group_type($type->type)) {
$return[$usage][] = $type->type;
}
}
else {
$type_usage = variable_get('og_content_type_usage_'. $type->type, 'omitted');
$return[$type_usage][] = $type->type;
}
}
return isset($return[$usage]) ? $return[$usage] : array();
}
// returns TRUE if node type should generate email notifications when posted to a group.
function og_is_mail_type($type) {
$usage = variable_get('og_content_type_usage_'. $type, 'omitted');
return strpos($usage, 'mail') && !strpos($usage, 'nomail') ? TRUE : FALSE;
}
// returns TRUE if node type lets all subscribers edit the node.
function og_is_wiki_type($type) {
$usage = variable_get('og_content_type_usage_'. $type, 'omitted');
return strpos($usage, 'wiki') ? TRUE : FALSE;
}
// returns TRUE if node type can be posted into a group.
function og_is_group_post_type($type) {
$usage = variable_get('og_content_type_usage_'. $type, 'omitted');
return strpos($usage, 'group_post') !== FALSE ? TRUE : FALSE;
}
function og_is_omitted_type($type) {
return variable_get('og_content_type_usage_'. $type, 'omitted') == 'omitted' ? TRUE : FALSE;
}
/**
* API function for determining whether a given node type has been designated
* by admin to behave as a group node (i.e. a container).
*
* @param string $type
* @return boolean
*/
function og_is_group_type($type) {
return variable_get('og_content_type_usage_'. $type, 'omitted') == 'group' ? TRUE : FALSE;
}
/**
* Menu callback. Render group feed.
*/
function og_feed($node) {
$view = views_get_view(variable_get('og_home_page_view', 'og_ghp_ron'));
$view->is_cacheable = FALSE;
$view->set_display('feed');
// TODOL: not working
$view->override_path = "node/$node->nid";
$view->set_arguments(array($node->nid));
$view->display['feed']->display_options['style_options']['description'] = $node->og_description;
print $view->render();
}
/**
* Implementation of hook_block().
*/
function og_block($op = 'list', $delta = 0, $edit = array()) {
if ($op == 'list') {
$blocks[0]['info'] = t('Group details');
$blocks[0]['cache'] = BLOCK_NO_CACHE;
// $blocks[1] used to be the album block. We do not change the numbers to not confuse people who update.
// $blocks[2] used to be the group members block. This is now served by Views. We do not change the numbers to not confuse people who update.
$blocks[3]['info'] = t('New groups');
$blocks[3]['cache'] = BLOCK_CACHE_PER_USER;
// Now provided by og_views. Please don't reuse this number 4
// $blocks[4]['info'] = t('My groups');
$blocks[5]['info'] = t('Group notifications');
$blocks[5]['cache'] = BLOCK_NO_CACHE;
// $blocks[6]['info'] = t('Group network');
// $blocks[6]['cache'] = BLOCK_CACHE_PER_USER;
// Auto-enable the group blocks for fresh installations.
$blocks[0]['status'] = 1;
$blocks[0]['region'] = 'left';
$blocks[0]['weight'] = -2;
$blocks[5]['status'] = 1;
$blocks[5]['region'] = 'left';
$blocks[5]['weight'] = -1;
return $blocks;
}
elseif ($op == 'view') {
switch ($delta) {
case 0:
return og_block_details();
case 3:
return og_block_new();
case 5:
return og_block_notifications();
case 6:
return og_block_users_network();
}
}
elseif ($op == 'configure') {
switch ($delta) {
case 2:
$items['og_block_cnt'] = array(
'#type' => 'textfield',
'#title' => t('Maximum number of members to show'),
'#default_value' => variable_get("og_block_cnt_$delta", 10),
'#size' => 5,
);
$items['og_block_subscribers_is_admin'] = array(
'#type' => 'checkboxes',
'#title' => t('Group roles'),
'#default_value' => variable_get("og_block_subscribers_is_admin", array('members', 'admins')),
'#options' => array('members' => t('Standard members'), 'admins' => t('Administrators')),
'#description' => t('You may specify which types of group members appear in the listing.'),
);
return $items;
case 3:
return array('og_block_cnt' => array('#type' => 'textfield', '#title' => t('Maximum number of groups to show'), '#default_value' => variable_get("og_block_cnt_$delta", 10), '#size' => 5, '#maxlength' => 255));
}
}
elseif ($op == 'save') {
switch ($delta) {
case 2:
if (isset($edit['og_block_subscribers_is_admin'])) {
variable_set("og_block_subscribers_is_admin", array_filter($edit['og_block_subscribers_is_admin']));
}
if (isset($edit['og_block_cnt'])) {
variable_set("og_block_cnt_$delta", $edit['og_block_cnt']);
}
break;
case 3:
if (isset($edit['og_block_cnt'])) {
variable_set("og_block_cnt_$delta", $edit['og_block_cnt']);
}
break;
}
}
}
function og_block_notifications() {
global $user;
if ($groupnode = og_get_group_context()) {
$content = t('This group offers a !groupfeed and an !email.', array('!groupfeed' => l(t('RSS feed'), "node/$groupnode->nid/feed"), '!email' => l(t('email subscription'), 'og/manage/'. $groupnode->nid)));
// NOTE: See og.css for styling specific to these lists
$content .= ' '. t('Or subscribe to these personalized, sitewide feeds:');
$inline = array('class' => 'links inline');
if ($user->uid) {
$l1[] = array('title' => t('Feed'), 'href' => 'group/myunread/feed');
$l1[] = array('title' => t('Page'), 'href' => 'group/myunread');
$links['my_unread'] = t('My unread:') .' '. theme('links', $l1, $inline);
$l2[] = array('title' => t('Feed'), 'href' => 'group/mytracker/feed');
$l2[] = array('title' => t('Page'), 'href' => 'group/mytracker');
$links['my_group'] = t('My group:') .' '. theme('links', $l2, $inline);
}
$l3[] = array('title' => t('Feed'), 'href' => 'group/tracker/feed');
$l3[] = array('title' => t('Page'), 'href' => 'group/tracker');
$links['all_posts'] = array('data' => t('All posts:') .' '. theme('links', $l3, $inline));
$content .= theme('item_list', $links);
$block['content'] = $content;
$block['subject'] = t('Group notifications');
return $block;
}
}
/**
* Return code that emits an XML icon. TODOL: this opml icon belongs in theme.inc
*/
function theme_opml_icon($url) {
if ($image = theme('image', drupal_get_path('module', 'og'). '/opml.gif', t('OPML file'), t('OPML file'))) {
return ''. $image. '';
}
}
function og_block_new() {
list($types, $in) = og_get_sql_args();
$sql = "SELECT COUNT(*) FROM {node} n INNER JOIN {og} og ON n.nid = og.nid WHERE og.directory=1 AND n.type $in AND n.status = 1";
$cnt = db_result(db_query(db_rewrite_sql($sql), $types));
if ($cnt > 0) {
$max = variable_get('og_block_cnt_3', 10);
$sql = "SELECT n.nid, n.title FROM {node} n INNER JOIN {og} og ON n.nid = og.nid WHERE n.status = 1 AND n.type $in AND og.directory=1 ORDER BY nid DESC";
$result = db_query_range(db_rewrite_sql($sql), $types, 0, $max);
$output = node_title_list($result);
if ($cnt > $max) {
$output .= ''. l(t('more'), 'og', array('title' => t('Browse the newest groups.'))) .'
';
}
$block['subject'] = t('New groups');
$block['content'] = $output;
return $block;
}
}
function og_block_details() {
global $user;
// Only display group details if we have a group context.
if (($node = og_get_group_context()) && node_access('view', $node)) {
$suffix = '';
list($txt, $subscription) = og_subscriber_count_link($node);
if ($subscription == 'active' || user_access('administer nodes')) {
$links = module_invoke_all('og_create_links', $node);
// We want to open this up for OG_INVITE_ONLY but we need to handle invitation workflow much better. See http://drupal.org/node/170332
if ($node->og_selective < OG_INVITE_ONLY) {
$links['invite'] = l(t('Invite friend'), "og/invite/$node->nid");
}
$links['subscribers'] = $txt;
$links['manager'] = t('Manager:') .' '. theme('username', $node);
// Site admins get a Join link if they are not yet subscribed.
$subscribe = isset($subscription) && og_is_group_member($node->nid, FALSE) ? l(t('My membership'), "og/manage/$node->nid") : og_subscribe_link($node);
if(isset($subscribe)) {
$links['my_membership'] = $subscribe;
}
if (module_exists('search') && user_access('search content')) {
$suffix = drupal_get_form('og_search_form', $node);
}
}
elseif ($subscription == 'requested') {
$links['approval'] = t('Your membership request awaits approval.');
$links['delete'] = l(t('Delete request'), "og/unsubscribe/$node->nid", array('query' => 'destination=og'));
}
elseif (!$user->uid) {
$dest = drupal_get_destination();
$links['must_login'] = t('You must register/login in order to post into this group.', array('!register' => url("user/register", array('query' => $dest)), '!login' => url("user/login", array('query' => $dest))));
}
elseif ($node->og_selective < OG_INVITE_ONLY) {
$links['subscribe'] = og_subscribe_link($node);
}
elseif ($node->og_selective == OG_INVITE_ONLY) {
$links['closed'] = t('This is an @invite group. The group administrators add/remove members as needed.', array('@invite' => t('invite only')));
}
elseif ($node->og_selective == OG_CLOSED) {
$links['closed'] = t('This is a @closed group. The group administrators add/remove members as needed.', array('@closed' => t('closed')));
}
// Modify these links by reference. If you want control of the whole block, see og_block_details().
drupal_alter('og_links', $links);
$block['content'] = theme('item_list', $links). $suffix;
$block['subject'] = l($node->title, "node/$node->nid");
return $block;
}
}
/**
* Determine the number of active and pending members and the current user's membership state.
*
* @return array
* An array containing two strings. One for the number of members and another containing 'active' or 'requested'
*/
function og_subscriber_count_link($node) {
global $user;
$result = db_query(og_list_users_sql(0, 0, NULL), $node->nid);
$cntpending = $cntall = 0;
$subscription = '';
while ($row = db_fetch_object($result)) {
$cntall++;
if ($row->is_active == 0) {
$cntpending++;
}
if ($row->uid == $user->uid) {
if ($row->is_active) {
$subscription = 'active';
}
else {
$subscription = 'requested';
}
}
}
$txt = format_plural($cntall-$cntpending, '1 member', '@count members');
$txt = og_is_picture() ? l($txt, "og/users/$node->nid/faces") : l($txt, "og/users/$node->nid");
$txt .= $cntpending ? " ($cntpending)" : '';
return array($txt, $subscription);
}
function og_subscribe_link($node) {
if ($node->og_selective == OG_MODERATED) {
$txt = t('Request membership');
}
elseif ($node->og_selective == OG_OPEN) {
$txt = t('Join');
}
if(isset($txt))
return l($txt, "og/subscribe/$node->nid", array('attributes' => array('rel' => 'nofollow'), 'query' => drupal_get_destination()));
}
// $group is an object containing a group node.
// TODO: Make this a proper menu
function og_og_create_links($group) {
global $user;
$post_types = og_get_types('group_post');
$types = node_get_types();
foreach ($post_types as $post_type) {
// We used to check for node_access(create) but then node admins would get a false positive and see node types that they could not create.
// When this becomes a proper menu in D6, we get sorting for free
$type_name = $types[$post_type]->name;
$type_url_str = str_replace('_', '-', $post_type);
if (module_invoke($types[$post_type]->module, 'access', 'create', $post_type, $user)) {
$links["create_$post_type"] = l(t('Create !type', array('!type' => $type_name)), "node/add/$type_url_str", array(
'title' => t('Add a new !s in this group.', array('!s' => $type_name)),
'query' => "gids[]=$group->nid",
));
}
}
return isset($links) ? $links : array();
}
function og_search_form($form_state, $group) {
$form_state['keys'] = array(
'#type' => 'textfield',
'#title' => '',
'#description' => '',
'#size' => 19,
'#maxlength' => 255,
);
$form_state['submit'] = array(
'#type' => 'submit',
'#value' => t('Search'),
);
$form_state['#pre_render'][] = 'og_search_form_pre_render';
$form_state['#method'] = 'get';
$form_state['#action'] = url("og/search/$group->nid");
return $form_state;
}
// Clean up query string like Views does.
function og_search_form_pre_render($form_state) {
// unset($form_state['form_build_id'], $form_state['form_token'], $form_state['form_id']);
return $form_state;
}
function og_is_picture() {
return variable_get('user_pictures', 0);
}
// TODOL: maybe use a custom theme('mark') here?
// Mark the current user's membership in a given group if it is pending.
function theme_og_format_subscriber_status($group) {
if (!$group['is_active']) {
return ' '. t('(pending approval)');
}
}
/**
* Implementation of hook_xmlrpc(). /*
*
*/
function og_xmlrpc() {
module_load_include('inc', 'og', 'og_xmlrpc');
return array(
array(
'og.subscribe_user',
'og_xmlrpc_subscribe_user',
array('struct', 'string', 'string', 'int', 'int'),
t('Add a user to a group.')),
array(
'og.getAllSubscribers',
'og_xmlrpc_get_all_subscribers',
array('array', 'string', 'string', 'int', 'int', 'int'),
t('All members for a given group.')),
array(
'og.getUserGroups',
'og_xmlrpc_get_user_groups',
array('array', 'string', 'string', 'int'),
t('Retrieve the group memberships for a given user.')),
);
}
/**
* Implementation of hook_token_list() for og specific tokens /*
*/
function og_token_list($type = 'all') {
if ($type == 'node' || $type == 'all') {
$tokens['node']['ogname'] = t('Title of top group');
$tokens['node']['ogname-raw'] = t('Unfiltered title of top group. WARNING - raw user input.');
$tokens['node']['og-id'] = t('ID of top group');
return $tokens;
}
}
/**
* Implementation of hook_token_values() for og specific tokens
*/
function og_token_values($type, $object = NULL) {
switch ($type) {
case 'node':
if (is_array($object->og_groups)) {
$gids = array_filter($object->og_groups);
foreach ($gids as $gid) {
$title = db_result(db_query("SELECT title FROM {node} WHERE nid = %d", $gid));
$values['ogname'] = check_plain($title);
$values['ogname-raw'] = $title;
$values['og-id'] = $gid;
break;
}
return $values;
}
break;
}
// No group info found. Return defaults.
$values['ogname'] = '';
$values['ogname-raw'] = '';
$values['og-id'] = '';
return $values;
}
function og_requirements($phase) {
$requirements = array();
// Ensure translations don't break at install time
$t = get_t();
if ($phase == 'runtime') {
$og_types = og_get_types('group');
$all_types = array_keys(node_get_types('types'));
if (!count(array_intersect($og_types, $all_types))) {
$requirements['og_group_types'] = array(
'title' => $t('Organic groups group type'),
'value' => $t('You have no node types which are acting as groups. See the Notes section of the !readme and the Content types fieldset at top of OG settings.', array('!readme' => og_readme(), '!settings' => url('admin/og/og'))),
'severity' => REQUIREMENT_ERROR,
);
}
if (!module_exists('job_queue')) {
$requirements['og_modules'] = array(
'title' => $t('Organic groups modules'),
'value' => $t('Organic groups works best when !job_queue.module is enabled. See the Integration section of the !readme.', array('!job_queue' => l('job_queue.module', 'http://drupal.org/project/job_queue'), '!readme' => og_readme())),
'severity' => REQUIREMENT_INFO
);
}
if (!module_exists('og_access')) {
$requirements['og_access'] = array(
'title' => $t('Organic groups access control'),
'value' => $t('Organic groups access control module is disabled. See the !modules.', array('!settings' => l($t('modules page'), 'admin/build/modules'))),
'severity' => REQUIREMENT_INFO
);
}
}
return $requirements;
}
function og_readme() {
global $base_path;
// this link has to work when clean urls are disabled and drupal in subdir.
$href = drupal_get_path('module', 'og'). '/README.txt';
$link = "". t('README file'). '';
return $link;
}
/**
* Get a private token used to protect links from spoofing - CSRF.
*/
function og_get_token($nid) {
return drupal_get_token($nid);
}
/**
* Check to see if a token value matches the specified node.
*/
function og_check_token($token, $seed) {
return drupal_get_token($seed) == $token;
}