/** * stamp an article * * This function is used to change various dates for one article. * * [*] If a publication date is provided, it is saved along the article. * An optional expiry date will be saved as well. * * [*] If only an expiry date is provided, it is saved along the article. * * [*] If no date is provided, the review field is updated to the current date and time. * * Dates are supposed to be in UTC time zone. * * The name of the surfer is registered as the official publisher. * As an alternative, publisher attributes ('name', 'id' and 'address') can be provided * in parameters. * * @param int the id of the item to publish * @param string the target publication date, if any * @param string the target expiration date, if any * @param array attributes of the publisher, if any * @return string either a null string, or some text describing an error to be inserted into the html response * * @see articles/publish.php * @see sections/manage.php **/ public static function stamp($id, $publication = NULL, $expiry = NULL, $publisher = NULL) { global $context; // id cannot be empty if (!$id || !is_numeric($id)) { return i18n::s('No item has the provided id.'); } // server offset $server_offset = 0; if (isset($context['gmt_offset'])) { $server_offset = intval($context['gmt_offset']); } // surfer offset $surfer_offset = Surfer::get_gmt_offset(); // no publication time is provided if (!isset($publication) || !$publication) { $publication_stamp = 0; } elseif (preg_match('/GMT$/', $publication) && strlen($publication) == 19) { // YYMMDD-HH:MM:SS GMT -> HH, MM, SS, MM, DD, YY $publication_stamp = gmmktime(intval(substr($publication, 7, 2)), intval(substr($publication, 10, 2)), intval(substr($publication, 13, 2)), intval(substr($publication, 2, 2)), intval(substr($publication, 4, 2)), intval(substr($publication, 0, 2))); // time()-like stamp } elseif (intval($publication) > 1000000000) { // adjust to UTC time zone $publication_stamp = intval($publication) + $context['gmt_offset'] * 3600; // YYYY-MM-DD HH:MM:SS, or a string that can be readed } elseif (($publication_stamp = SQL::strtotime($publication)) != -1) { } else { return sprintf(i18n::s('"%s" is not a valid date'), $publication); } // no expiry date if (!isset($expiry) || !$expiry) { $expiry_stamp = 0; } elseif (preg_match('/GMT$/', $expiry) && strlen($expiry) == 19) { // YYMMDD-HH:MM:SS GMT -> HH, MM, SS, MM, DD, YY $expiry_stamp = gmmktime(substr($expiry, 7, 2), substr($expiry, 10, 2), substr($expiry, 13, 2), substr($expiry, 2, 2), substr($expiry, 4, 2), substr($expiry, 0, 2)); // time()-like stamp } elseif (intval($expiry) > 1000000000) { // adjust to server time zone $expiry_stamp = intval($expiry) + $context['gmt_offset'] * 3600; // YYYY-MM-DD HH:MM:SS, or a string that can be readed } elseif (($expiry_stamp = SQL::strtotime($expiry)) != -1) { } else { return sprintf(i18n::s('"%s" is not a valid date'), $expiry); } // review date $review_stamp = 0; if (!$publication_stamp && !$expiry_stamp) { $review_stamp = time(); } // shape the query $query = array(); if ($publication_stamp > 0) { $query[] = "publish_name='" . SQL::escape(isset($publisher['name']) ? $publisher['name'] : Surfer::get_name()) . "'," . "publish_id=" . SQL::escape(isset($publisher['id']) ? $publisher['id'] : Surfer::get_id()) . "," . "publish_address='" . SQL::escape(isset($publisher['address']) ? $publisher['address'] : Surfer::get_email_address()) . "'," . "publish_date='" . gmstrftime('%Y-%m-%d %H:%M:%S', $publication_stamp) . "'," . "edit_name='" . SQL::escape(isset($publisher['name']) ? $publisher['name'] : Surfer::get_name()) . "'," . "edit_id=" . SQL::escape(isset($publisher['id']) ? $publisher['id'] : Surfer::get_id()) . "," . "edit_address='" . SQL::escape(isset($publisher['address']) ? $publisher['address'] : Surfer::get_email_address()) . "'," . "edit_action='article:publish'," . "edit_date='" . gmstrftime('%Y-%m-%d %H:%M:%S') . "'"; } if ($expiry_stamp > 0) { $query[] = "expiry_date='" . gmstrftime('%Y-%m-%d %H:%M:%S', $expiry_stamp) . "'"; } if ($review_stamp > 0) { $query[] = "review_date='" . gmstrftime('%Y-%m-%d %H:%M:%S', $review_stamp) . "'"; } // update an existing record $query = "UPDATE " . SQL::table_name('articles') . " SET " . implode(',', $query) . " WHERE id = " . SQL::escape($id); if (SQL::query($query) === FALSE) { return NULL; } // remember the publication in weekly and monthly categories if ($publication_stamp > 0) { Categories::remember('article:' . $id, gmstrftime('%Y-%m-%d %H:%M:%S', $publication_stamp)); } // end of job return NULL; }
/** * remember the last action for this category * * @param string the description of the last action * @param string the id of the item related to this update * @param boolean TRUE to not change the edit date of this anchor, default is FALSE * * @see shared/anchor.php */ function touch($action, $origin = NULL, $silently = FALSE) { global $context; // don't go further on import if (preg_match('/import$/i', $action)) { return; } // no category bound if (!isset($this->item['id'])) { return; } // sanity check if (!$origin) { logger::remember('categories/category.php: unexpected NULL origin at touch()'); return; } // components of the query $query = array(); // append a reference to a new image to the description if ($action == 'image:create') { if (!Codes::check_embedded($this->item['description'], 'image', $origin)) { // the overlay may prevent embedding if (is_object($this->overlay) && !$this->overlay->should_embed_files()) { } else { // list has already started if (preg_match('/\\[image=[^\\]]+?\\]\\s*$/', $this->item['description'])) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' [image=' . $origin . ']') . "'"; } else { $query[] = "description = '" . SQL::escape($this->item['description'] . "\n\n" . '[image=' . $origin . ']') . "'"; } } } // also use it as thumnail if none has been defined yet if (!isset($this->item['thumbnail_url']) || !trim($this->item['thumbnail_url'])) { include_once $context['path_to_root'] . 'images/images.php'; if (($image = Images::get($origin)) && ($url = Images::get_thumbnail_href($image))) { $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } } // refresh stamp only if image update occurs within 6 hours after last edition if (SQL::strtotime($this->item['edit_date']) + 6 * 60 * 60 < time()) { $silently = TRUE; } // suppress a reference to an image that has been deleted } elseif ($action == 'image:delete') { // suppress reference in main description field $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'image', $origin)) . "'"; // suppress references as icon and thumbnail as well include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { if ($url = Images::get_icon_href($image)) { if ($this->item['icon_url'] == $url) { $query[] = "icon_url = ''"; } if ($this->item['thumbnail_url'] == $url) { $query[] = "thumbnail_url = ''"; } } if ($url = Images::get_thumbnail_href($image)) { if ($this->item['icon_url'] == $url) { $query[] = "icon_url = ''"; } if ($this->item['thumbnail_url'] == $url) { $query[] = "thumbnail_url = ''"; } } } // set an existing image as the category icon } elseif ($action == 'image:set_as_icon') { include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { if ($url = Images::get_icon_href($image)) { $query[] = "icon_url = '" . SQL::escape($url) . "'"; } // also use it as thumnail if none has been defined yet if (!(isset($this->item['thumbnail_url']) && trim($this->item['thumbnail_url'])) && ($url = Images::get_thumbnail_href($image))) { $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } } $silently = TRUE; // set an existing image as the category thumbnail } elseif ($action == 'image:set_as_thumbnail') { include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { if ($url = Images::get_thumbnail_href($image)) { $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } } $silently = TRUE; // append a new image, and set it as the article thumbnail } elseif ($action == 'image:set_as_both') { if (!Codes::check_embedded($this->item['description'], 'image', $origin)) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' [image=' . $origin . ']') . "'"; } include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { if ($url = Images::get_thumbnail_href($image)) { $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } } elseif ($origin) { $query[] = "thumbnail_url = '" . SQL::escape($origin) . "'"; } // do not remember minor changes $silently = TRUE; // add a reference to a new table in the category description } elseif ($action == 'table:create') { if (!Codes::check_embedded($this->item['description'], 'table', $origin)) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' [table=' . $origin . ']') . "'"; } // suppress a reference to a table that has been deleted } elseif ($action == 'table:delete') { $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'table', $origin)) . "'"; } // stamp the update if (!$silently) { $query[] = "edit_name='" . Surfer::get_name() . "'," . "edit_id=" . Surfer::get_id() . "," . "edit_address='" . Surfer::get_email_address() . "'," . "edit_action='{$action}'," . "edit_date='" . strftime('%Y-%m-%d %H:%M:%S') . "'"; } // ensure we have a valid update query if (!@count($query)) { return; } // update the anchor category $query = "UPDATE " . SQL::table_name('categories') . " SET " . implode(', ', $query) . " WHERE id = " . SQL::escape($this->item['id']); if (SQL::query($query) === FALSE) { return; } // always clear the cache, even on no update Categories::clear($this->item); // get the parent if (!$this->anchor) { $this->anchor = Anchors::get($this->item['anchor']); } // propagate the touch upwards silently -- we only want to purge the cache if (is_object($this->anchor)) { $this->anchor->touch('category:update', $this->item['id'], TRUE); } }
$anchor = 'section:' . $fields['id']; } } // archive the letter $context['text'] .= i18n::s('Archiving the new letter') . BR . "\n"; // save the letter as a published article, but don't use special categories $fields = array(); $fields['anchor'] = $anchor; $fields['title'] = $_REQUEST['letter_title']; $label = $_REQUEST['letter_recipients']; if ($_REQUEST['letter_recipients'] == 'custom' && isset($_REQUEST['mail_to'])) { $label = $_REQUEST['mail_to']; } $fields['introduction'] = sprintf(i18n::c('Sent %s to "%s"'), Skin::build_date(time(), 'full', $context['preferred_language']), $label); $fields['description'] = $_REQUEST['letter_body']; $fields['publish_name'] = Surfer::get_name(); $fields['publish_id'] = Surfer::get_id(); $fields['publish_address'] = Surfer::get_email_address(); $fields['publish_date'] = gmstrftime('%Y-%m-%d %H:%M:%S'); $fields['id'] = Articles::post($fields); // from: from configuration files if (isset($context['letter_reply_to']) && $context['letter_reply_to']) { $from = $context['letter_reply_to']; } elseif (isset($context['mail_from']) && $context['mail_from']) { $from = $context['mail_from']; } else { $from = $context['site_name']; } // to: build the list of recipients $recipients = array(); switch ($_REQUEST['letter_recipients']) {
} // ensure we have a valid layout for articles if (!isset($_REQUEST['root_articles_layout']) || !$_REQUEST['root_articles_layout'] || !preg_match('/(alistapart|compact|custom|daily|decorated|digg|hardboiled|newspaper|no_articles|slashdot)/', $_REQUEST['root_articles_layout'])) { $_REQUEST['root_articles_layout'] = 'daily'; } elseif ($_REQUEST['root_articles_layout'] == 'custom') { if (isset($_REQUEST['home_custom_layout']) && $_REQUEST['home_custom_layout']) { $_REQUEST['root_articles_layout'] = basename(strip_tags($_REQUEST['home_custom_layout'])); } else { $_REQUEST['root_articles_layout'] = 'daily'; } } // backup the old version Safe::unlink($context['path_to_root'] . 'parameters/root.include.php.bak'); Safe::rename($context['path_to_root'] . 'parameters/root.include.php', $context['path_to_root'] . 'parameters/root.include.php.bak'); // build the new configuration file $content = '<?php' . "\n" . '// This file has been created by the configuration script configure.php' . "\n" . '// on ' . gmdate("F j, Y, g:i a") . ' GMT, for ' . Surfer::get_name() . '. Please do not modify it manually.' . "\n" . 'global $context;' . "\n" . '$context[\'root_articles_layout\']=\'' . addcslashes($_REQUEST['root_articles_layout'], "\\'") . "';\n"; if (isset($_REQUEST['root_articles_count_at_home']) && intval($_REQUEST['root_articles_count_at_home'])) { $content .= '$context[\'root_articles_count_at_home\']=\'' . intval($_REQUEST['root_articles_count_at_home']) . "';\n"; } if (isset($_REQUEST['root_cover_at_home'])) { $content .= '$context[\'root_cover_at_home\']=\'' . addcslashes($_REQUEST['root_cover_at_home'], "\\'") . "';\n"; } if (isset($_REQUEST['root_flash_at_home'])) { $content .= '$context[\'root_flash_at_home\']=\'' . addcslashes($_REQUEST['root_flash_at_home'], "\\'") . "';\n"; } if (isset($_REQUEST['root_gadget_boxes_at_home'])) { $content .= '$context[\'root_gadget_boxes_at_home\']=\'' . addcslashes($_REQUEST['root_gadget_boxes_at_home'], "\\'") . "';\n"; } if (isset($_REQUEST['root_featured_layout'])) { $content .= '$context[\'root_featured_layout\']=\'' . addcslashes($_REQUEST['root_featured_layout'], "\\'") . "';\n"; }
* @license http://www.gnu.org/copyleft/lesser.txt GNU Lesser General Public License */ // common definitions and initial processing include_once '../shared/global.php'; include_once 'notifications.php'; // ensure browser always look for fresh data http::expire(0); // surfer has to be logged --provide a short response if (!Surfer::get_id()) { Safe::header('Status: 401 Unauthorized', TRUE, 401); die(i18n::s('You are not allowed to perform this operation.')); // a new notification has been submitted } elseif (isset($_REQUEST['recipient']) && isset($_REQUEST['type'])) { // record the notification $fields = array(); $fields['nick_name'] = Surfer::get_name(); $fields['recipient'] = $_REQUEST['recipient']; $fields['type'] = $_REQUEST['type']; if (isset($_REQUEST['address'])) { $fields['address'] = encode_link($_REQUEST['address']); } if (isset($_REQUEST['message'])) { $fields['message'] = strip_tags($_REQUEST['message']); } // vaidate notification attributes switch ($fields['type']) { case 'browse': if (!isset($_REQUEST['address'])) { Safe::header('Status: 400 Bad Request', TRUE, 400); die(i18n::s('Request is invalid.')); }
$label = i18n::s('Message title'); if (is_object($overlay)) { $title = $overlay->get_live_title($item); } else { $title = $item['title']; } $title = sprintf(i18n::c('Invitation: %s'), $title); $input = '<input type="text" name="subject" size="50" maxlength="255" value="' . encode_field($title) . '" />'; $fields[] = array($label, $input); // default message content $content = ''; if (is_callable(array($overlay, 'get_invite_default_message'))) { $content = $overlay->get_invite_default_message(); } if (!$content) { $content = '<p>' . i18n::c('I would like to invite you to the following page.') . '</p>' . '<p><a href="' . Sections::get_permalink($item) . '">' . $item['title'] . '</a></p>' . '<p>' . i18n::c('Please let me thank you for your involvement.') . '</p>' . '<p>' . Surfer::get_name() . '</p>'; } // the message $label = i18n::s('Message content'); $input = Surfer::get_editor('message', $content); $fields[] = array($label, $input); // build the form $context['text'] .= Skin::build_form($fields); // // bottom commands // $menu = array(); // the submit button $menu[] = Skin::build_submit_button(i18n::s('Submit'), i18n::s('Press [s] to submit data'), 's'); // cancel button if (isset($item['id'])) {
} // display the form if ($with_form) { // by default it will be a group space if (!isset($item['articles_layout'])) { $item['articles_layout'] = 'group'; } // default title if (!isset($item['title'])) { // first section if (!isset($existing_sections) || !$existing_sections) { $item['title'] = sprintf(i18n::s('The personal space of %s'), Surfer::get_name()); } elseif ($existing_sections == 1) { $item['title'] = sprintf(i18n::s('Another personal space of %s'), Surfer::get_name()); } else { $item['title'] = sprintf(i18n::s('Another personal space of %s (%d)'), Surfer::get_name(), $existing_sections + 1); } } // the form to edit a section $context['text'] .= '<form method="post" action="' . $context['script_url'] . '" onsubmit="return validateDocumentPost(this)" id="main_form"><div>'; // layout for related articles $label = i18n::s('Purpose'); $input = i18n::s('What are you aiming to create?'); $input .= BR . '<input type="radio" name="space_type" value="group" checked="checked"'; $input .= EOT . i18n::s('A group, for people interested in some topic'); $input .= BR . '<input type="radio" name="space_type" value="blog"'; $input .= EOT . i18n::s('A blog, to express your thoughts and to lead the pack'); $input .= BR . '<input type="radio" name="space_type" value="project"'; $input .= EOT . i18n::s('A project, to support teamwork'); $fields[] = array($label, $input); // the title
/** * remember the last action for this section * * @see articles/article.php * @see shared/anchor.php * * @param string the description of the last action * @param string the id of the item related to this update * @param boolean TRUE to not change the edit date of this anchor, default is FALSE */ function touch($action, $origin = NULL, $silently = FALSE) { global $context; // we make extensive use of comments below include_once $context['path_to_root'] . 'comments/comments.php'; // don't go further on import if (preg_match('/import$/i', $action)) { return; } // no section bound if (!isset($this->item['id'])) { return; } // delegate to overlay if (is_object($this->overlay) && $this->overlay->touch($action, $origin, $silently) === false) { return; // stop on false } // sanity check if (!$origin) { logger::remember('sections/section.php: unexpected NULL origin at touch()'); return; } // components of the query $query = array(); // a new page has been added to the section if ($action == 'article:publish' || $action == 'article:submit') { // limit the number of items attached to this section if (isset($this->item['maximum_items']) && $this->item['maximum_items'] > 10) { Articles::purge_for_anchor('section:' . $this->item['id'], $this->item['maximum_items']); } // a new comment has been posted } elseif ($action == 'comment:create') { // purge oldest comments Comments::purge_for_anchor('section:' . $this->item['id']); // file upload } elseif ($action == 'file:create' || $action == 'file:upload') { // actually, several files have been added $label = ''; if (!$origin) { $fields = array(); $fields['anchor'] = 'section:' . $this->item['id']; $fields['description'] = i18n::s('Several files have been added'); $fields['type'] = 'notification'; Comments::post($fields); // one file has been added } elseif (!Codes::check_embedded($this->item['description'], 'embed', $origin) && ($item = Files::get($origin, TRUE))) { // this file is eligible for being embedded in the page if (isset($item['file_name']) && Files::is_embeddable($item['file_name'])) { // the overlay may prevent embedding if (is_object($this->overlay) && !$this->overlay->should_embed_files()) { } else { $label = '[embed=' . $origin . ']'; } // else add a comment to take note of the upload } elseif (Comments::allow_creation($this->item, null, 'section')) { $fields = array(); $fields['anchor'] = 'section:' . $this->item['id']; if ($action == 'file:create') { $fields['description'] = '[file=' . $item['id'] . ',' . $item['file_name'] . ']'; } else { $fields['description'] = '[download=' . $item['id'] . ',' . $item['file_name'] . ']'; } Comments::post($fields); } } // include flash videos in a regular page if ($label) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' ' . $label) . "'"; } // suppress references to a deleted file } elseif ($action == 'file:delete') { // suppress reference in main description field $text = Codes::delete_embedded($this->item['description'], 'download', $origin); $text = Codes::delete_embedded($text, 'embed', $origin); $text = Codes::delete_embedded($text, 'file', $origin); // save changes $query[] = "description = '" . SQL::escape($text) . "'"; // append a reference to a new image to the description } elseif ($action == 'image:create') { if (!Codes::check_embedded($this->item['description'], 'image', $origin)) { // the overlay may prevent embedding if (is_object($this->overlay) && !$this->overlay->should_embed_files()) { } else { // list has already started if (preg_match('/\\[image=[^\\]]+?\\]\\s*$/', $this->item['description'])) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' [image=' . $origin . ']') . "'"; } else { $query[] = "description = '" . SQL::escape($this->item['description'] . "\n\n" . '[image=' . $origin . ']') . "'"; } } } // also use it as thumnail if none has been defined yet if (!isset($this->item['thumbnail_url']) || !trim($this->item['thumbnail_url'])) { include_once $context['path_to_root'] . 'images/images.php'; if (($image = Images::get($origin)) && ($url = Images::get_thumbnail_href($image))) { $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } } // refresh stamp only if image update occurs within 6 hours after last edition if (SQL::strtotime($this->item['edit_date']) + 6 * 60 * 60 < time()) { $silently = TRUE; } // suppress a reference to an image that has been deleted } elseif ($action == 'image:delete') { // suppress reference in main description field $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'image', $origin)) . "'"; // suppress references as icon and thumbnail as well include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { if ($url = Images::get_icon_href($image)) { if ($this->item['icon_url'] == $url) { $query[] = "icon_url = ''"; } if ($this->item['thumbnail_url'] == $url) { $query[] = "thumbnail_url = ''"; } } if ($url = Images::get_thumbnail_href($image)) { if ($this->item['icon_url'] == $url) { $query[] = "icon_url = ''"; } if ($this->item['thumbnail_url'] == $url) { $query[] = "thumbnail_url = ''"; } } } // set an existing image as the section icon } elseif ($action == 'image:set_as_icon') { include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { if ($url = Images::get_icon_href($image)) { $query[] = "icon_url = '" . SQL::escape($url) . "'"; } // also use it as thumnail if none has been defined yet if (!(isset($this->item['thumbnail_url']) && trim($this->item['thumbnail_url'])) && ($url = Images::get_thumbnail_href($image))) { $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } } elseif ($origin) { $query[] = "icon_url = '" . SQL::escape($origin) . "'"; } $silently = TRUE; // set an existing image as the section thumbnail } elseif ($action == 'image:set_as_thumbnail') { include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { // use the thumbnail for large files, or the image itself for smaller files if ($image['image_size'] > $context['thumbnail_threshold']) { $url = Images::get_thumbnail_href($image); } else { $url = Images::get_icon_href($image); } $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } elseif ($origin) { $query[] = "thumbnail_url = '" . SQL::escape($origin) . "'"; } $silently = TRUE; // append a new image, and set it as the article thumbnail } elseif ($action == 'image:set_as_both') { if (!Codes::check_embedded($this->item['description'], 'image', $origin)) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' [image=' . $origin . ']') . "'"; } include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { // use the thumbnail for large files, or the image itself for smaller files if ($image['image_size'] > $context['thumbnail_threshold']) { $url = Images::get_thumbnail_href($image); } else { $url = Images::get_icon_href($image); } $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } elseif ($origin) { $query[] = "thumbnail_url = '" . SQL::escape($origin) . "'"; } // do not remember minor changes $silently = TRUE; // add a reference to a new table in the section description } elseif ($action == 'table:create') { if (!Codes::check_embedded($this->item['description'], 'table', $origin)) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' [table=' . $origin . ']') . "'"; } // suppress a reference to a table that has been deleted } elseif ($action == 'table:delete') { $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'table', $origin)) . "'"; } // stamp the update if (!$silently) { $query[] = "edit_name='" . SQL::escape(Surfer::get_name()) . "'," . "edit_id=" . SQL::escape(Surfer::get_id()) . "," . "edit_address='" . SQL::escape(Surfer::get_email_address()) . "'," . "edit_action='{$action}'," . "edit_date='" . SQL::escape(gmstrftime('%Y-%m-%d %H:%M:%S')) . "'"; } // update the database if (@count($query)) { $query = "UPDATE " . SQL::table_name('sections') . " SET " . implode(', ', $query) . " WHERE id = " . SQL::escape($this->item['id']); SQL::query($query); } // always clear the cache, even on no update Sections::clear($this->item); // get the parent if (!$this->anchor) { $this->anchor = Anchors::get($this->item['anchor']); } // propagate the touch upwards silently -- we only want to purge the cache if (is_object($this->anchor)) { $this->anchor->touch('section:touch', $this->item['id'], TRUE); } }
if (!strncmp($track, 'user:'******'user:'******'', $track))) && isset($user['email']) && $user['email'] && $user['without_alerts'] != 'Y') { // contact target user by e-mail $subject = sprintf(i18n::c('%s is following you'), strip_tags(Surfer::get_name())); // headline $headline = sprintf(i18n::c('%s is following you'), Surfer::get_link()); // information $message = '<p>' . sprintf(i18n::c('%s will receive notifications when you will update your followers at %s'), Surfer::get_name(), $context['site_name']) . '</p>'; // assemble main content of this message $message = Skin::build_mail_content($headline, $message); // a set of links $menu = array(); // call for action $link = Surfer::get_permalink(); $menu[] = Skin::build_mail_button($link, ucfirst(strip_tags(Surfer::get_name())), TRUE); // finalize links $message .= Skin::build_mail_menu($menu); // enable threading $headers = Mailer::set_thread('user:'******'id']); // sent by the server Mailer::notify(NULL, $user['email'], $subject, $message, $headers); } // feed-back to poster $context['text'] .= '<p>' . sprintf(i18n::s('You have been connected to %s.'), Skin::build_link($anchor->get_url(), $anchor->get_title())) . "</p>\n"; $menu[] = Skin::build_link(Users::get_url($track, 'track'), i18n::s('I have changed my mind'), 'span'); // we are tracking a page } else { // reference the anchor page if (is_object($anchor) && $anchor->is_viewable()) { $context['text'] .= '<p>' . Skin::build_link($anchor->get_url(), $anchor->get_title()) . "</p>\n";
// end of the installation } elseif (!file_exists('parameters/switch.on') && !file_exists('parameters/switch.off')) { // create the switch $content = '---------------------------------------------' . "\n" . 'YACS will process requests if this file is named switch.on,' . "\n" . 'and will redirect everything to control/closed.php if its name is changed to switch.off.' . "\n" . "\n" . 'Associates can use the script control/switch.php to stop and restart remotely.' . "\n" . '---------------------------------------------' . "\n"; if (!Safe::file_put_contents('parameters/switch.on', $content)) { // not enough rights to write the file Logger::error(i18n::s('ERROR: YACS cannot create the file parameters/switch.on to activate the server.')); // allow for a manual update $context['text'] .= '<p style="text-decoration: blink;">' . sprintf(i18n::s('To actually switch on the server, please copy and paste following lines by yourself in file %s.'), 'parameters/switch.on') . "</p>\n"; // content of the switch file $context['text'] .= '<pre>' . $content . "</pre>\n"; } // if there is no index at the upper level if (!file_exists($context['path_to_root'] . '../index.php') && ($content = Safe::file_get_contents($context['path_to_root'] . 'index.php'))) { // silently attempt to duplicate our index Safe::file_put_contents('../index.php', $content); // remember this for the next incremental update $content = '<?php' . "\n" . '// This file has been created by the setup script setup.php' . "\n" . '// on ' . gmdate("F j, Y, g:i a") . ' GMT, for ' . Surfer::get_name() . '. Please do not modify it manually.' . "\n" . '$context[\'home_at_root\']=\'Y\';' . "\n" . '$context[\'reference_server\']=\'' . addcslashes(i18n::s('www.yacs.fr'), "\\'") . "';\n" . '?>' . "\n"; Safe::file_put_contents('parameters/scripts.include.php', $content); } // the splash message $context['text'] .= sprintf(i18n::s("<p>You have passed through the several installation steps.</p>\nWhat do you want to do now?<ul>\n<li>Select %s for your site.</li>\n<li>Populate your site with the %s.</li>\n<li>Manage everything from the %s.</li>\n<li>Check the %s of this site.</li>\n<li>Review %s.</li>\n<li>%s.</li>\n<li>Look at the %s.</li>\n<li>Visit %s to learn more.</li>\n</ul>\n<p>Thank you for having selected to use YACS for your web site.</p>\n"), Skin::build_link('skins/', i18n::s('another skin')), Skin::build_link('help/populate.php', i18n::s('Content Assistant')), Skin::build_link('control/', i18n::s('Control Panel')), Skin::build_link($context['url_to_root'], i18n::s('front page')), Skin::build_link('users/view.php', i18n::s('your profile')), Skin::build_link('articles/edit.php', i18n::s('Add a page')), Skin::build_link('help/', i18n::s('Help index')), Skin::build_link(i18n::s('http://www.yacs.fr/'), i18n::s('www.yacs.fr'), 'external')) . "\n"; // no need for installation } else { // the splash message $context['text'] .= i18n::s('<p>Since basic configuration files exist on your server, it is likely that the installation has been achieved successfully. Click on the link below to modify the running parameters of your server.</p>') . "\n"; // to the control panel $context['text'] .= '<p><a href="control/">' . i18n::s('Control Panel') . "</a></p>\n"; } // render the skin render_skin();
/** * get profile address for this surfer, if known * * @return string web link to the target user profile, or NULL */ public static function get_permalink() { global $context; if (Surfer::get_id() && is_callable(array('Users', 'get_url'))) { return $context['url_to_home'] . $context['url_to_root'] . Users::get_url(Surfer::get_id(), 'view', Surfer::get_name()); } return NULL; }
/** * stop a meeting * */ function stop_meeting() { global $context; // move to the 'closed' status $fields = array('status' => 'stopped'); $this->set_values($fields); // track the end of the meeting include_once $context['path_to_root'] . 'comments/comments.php'; if (is_callable(array($this->anchor, 'get_reference')) && !$this->anchor->has_option('no_comments')) { $fields = array(); $fields['anchor'] = $this->anchor->get_reference(); $fields['description'] = sprintf(i18n::s('%s has stopped the meeting'), Surfer::get_name()); $fields['type'] = 'notification'; Comments::post($fields); } }
/** * scan a file for viruses * * This function connects to ClamAV daemon, if possible, to scan the referred file. * * @param string absolute path of the file to scan * @return string 'Y' if the file has been infected, '?' if clamav is not available, or 'N' if no virus has been found */ public static function has_virus($file) { global $context; // file scanning must be configured if (!isset($context['clamav_check']) || $context['clamav_check'] === 'N') { return 'N'; } // we can't connect to clamav daemon $server = 'localhost'; if (!($handle = Safe::fsockopen($server, 3310, $errno, $errstr, 1))) { if ($context['with_debug'] == 'Y') { Logger::remember('files/files.php: Unable to connect to CLAMAV daemon', '', 'debug'); } return '?'; } // ensure enough execution time Safe::set_time_limit(30); // scan uploaded file $request = 'SCAN ' . $file; fputs($handle, $request . CRLF); if ($context['with_debug'] == 'Y') { Logger::remember('files/files.php: CLAMAV ->', $request, 'debug'); } // expecting an OK if (($reply = fgets($handle)) === FALSE) { Logger::remember('files/files.php: No reply to SCAN command at ' . $server); fclose($handle); return '?'; } if ($context['with_debug'] == 'Y') { Logger::remember('files/files.php: CLAMAV <-', $reply, 'debug'); } // file has been infected! if (!stripos($reply, ': ok')) { Logger::remember('files/files.php: Infected upload by ' . Surfer::get_name()); fclose($handle); return 'Y'; } // everything is ok fclose($handle); return 'N'; }
Safe::header('Status: 401 Unauthorized', TRUE, 401); Logger::error(i18n::s('You are not allowed to perform this operation.')); // maybe this article cannot be modified anymore } elseif (isset($item['locked']) && $item['locked'] == 'Y' && !Surfer::is_empowered()) { Safe::header('Status: 401 Unauthorized', TRUE, 401); Logger::error(i18n::s('This page has been locked.')); // do the job } else { // attributes to change $fields = array(); $fields['id'] = $item['id']; $fields['anchor'] = $destination->get_reference(); // do the change if (Articles::put_attributes($fields)) { // only when comments are allowed if (!Articles::has_option('no_comments', $anchor, $item)) { // add a comment to make the move explicit include_once $context['path_to_root'] . 'comments/comments.php'; $fields = array(); $fields['anchor'] = 'article:' . $item['id']; $fields['description'] = sprintf(i18n::s('Moved by %s from %s to %s'), Surfer::get_name(), $anchor->get_title(), $destination->get_title()); Comments::post($fields); } // update previous container Cache::clear($anchor->get_reference()); // switch to the updated page Safe::redirect(Articles::get_permalink($item)); } } // render the skin render_skin();
/** * echo the standard footer * * Note that this one does not echo $context['page_footer'], and you have * to do it yourself. * * @param string footer prefix, if any * @param string footer suffix, if any */ public static function footer($prefix = '', $suffix = '') { global $context; // the last paragraph echo '<p>'; // add footer prefix echo $prefix; $details = array(); // execution time and surfer name, for logged user only (not for indexing robots!) if (is_callable(array('Surfer', 'get_name')) && is_callable(array('i18n', 's'))) { $execution_time = round(get_micro_time() - $context['start_time'], 2); $details[] = sprintf(i18n::s('page prepared in %.2f seconds for %s'), $execution_time, ucwords(Surfer::get_name())); } // site copyright if (isset($context['site_copyright']) && $context['site_copyright']) { $details[] = '© ' . $context['site_copyright'] . "\n"; } // a command to authenticate if (is_callable(array('Surfer', 'is_logged')) && !Surfer::is_logged() && is_callable(array('i18n', 's'))) { $details[] = Skin::build_link('users/login.php', i18n::s('login'), 'basic'); } // about this site if (is_callable(array('i18n', 's')) && is_callable(array('Articles', 'get_url'))) { $details[] = Skin::build_link(Articles::get_url('about'), i18n::s('about this site'), 'basic'); } // privacy statement if (is_callable(array('i18n', 's')) && is_callable(array('Articles', 'get_url'))) { $details[] = Skin::build_link(Articles::get_url('privacy'), i18n::s('privacy statement'), 'basic'); } // a reference to YACS if (is_callable(array('i18n', 's')) && $context['host_name'] != 'www.yacs.fr') { $details[] = sprintf(i18n::s('powered by %s'), Skin::build_link(i18n::s('http://www.yacs.fr/'), 'Yacs', 'external')); } // all our feeds if (is_callable(array('i18n', 's'))) { $details[] = Skin::build_link('feeds/', i18n::s('information channels'), 'basic'); } echo join(' - ', $details); // add footer suffix echo $suffix; // end of the last paragraph echo '</p>' . "\n"; }
} break; default: // user information $context['text'] .= '<b>' . sprintf(i18n::s('Bad hook type %s to %s for %s'), $hook['type'], $hook['script'], $hook['id']) . '</b>' . BR . "\n"; continue; } // append to hooks.xml $xml .= "<hook>\n"; foreach ($hook as $label => $value) { $xml .= "\t<" . $label . '>' . $value . '<' . $label . ">\n"; } $xml .= "</hook>\n\n"; } // the header section $content = '<?php' . "\n" . '// This file has been created by the script control/scan.php' . "\n" . '// on ' . gmdate("F j, Y, g:i a") . ' GMT, for ' . Surfer::get_name() . '. Please do not modify it manually.' . "\n" . "\n" . 'class Hooks {' . "\n\n"; // start the linking function $content .= "\t" . 'public static function link_scripts($id, $variant=\'list\') {' . "\n" . "\t\t" . 'global $local, $context;' . "\n\n" . "\t\t" . '$links = array();' . "\n\n" . "\t\t" . 'switch($id) {' . "\n\n"; // one linking item per id if (count($linked_items)) { foreach ($linked_items as $id => $item) { $content .= "\t\t" . 'case \'' . $id . '\':' . "\n" . $item . "\t\t\tbreak;\n\n"; } } // return the array itself $content .= "\t\t}\n\n\t\t" . 'if($variant == \'array\')' . "\n" . "\t\t\t" . 'return $links;' . "\n\n"; // no linking hook has been found $content .= "\t\t" . 'if(!count($links))' . "\n" . "\t\t\t" . 'return NULL;' . "\n\n"; // format the result $content .= "\t\t" . '$text = \'\';' . "\n\n" . "\t\t" . 'if($variant == \'list\')' . "\n" . "\t\t\t" . '$text .= \'<ul>\';' . "\n\n" . "\t\t" . 'foreach($links as $script => $label) {' . "\n" . "\t\t\t" . '$text .= \'<li>\'.Skin::build_link($script, $label, \'shortcut\');' . "\n" . "\t\t\t" . 'if($descriptions[$script])' . "\n" . "\t\t\t\t" . '$text .= \' - \'.$descriptions[$script];' . "\n" . "\t\t\t" . 'if($sources[$script])' . "\n" . "\t\t\t\t" . '$text .= \' (\'.$sources[$script].\')\';' . "\n" . "\t\t\t" . '$text .= \'</li>\';' . "\n" . "\t\t" . '}' . "\n\n" . "\t\t" . 'if($variant == \'list\')' . "\n" . "\t\t\t" . '$text .= \'</ul>\';' . "\n\n" . "\t\t" . 'return $text;' . "\n\n"; // end the linking function
/** * remember the last action for this article * * This function is called by related items. What does it do? * - On image creation, the adequate code is added to the description field to let the image be displayed inline * - On icon selection, the icon field is updated * - On thumbnail image selection, the thumbnail image field is updated * - On location creation, some code is inserted in the description field to display location name inline * - On table creation, some code is inserted in the description field to display the table inline * * @see articles/article.php * @see articles/edit.php * @see shared/anchor.php * * @param string one of the pre-defined action code * @param string the id of the item related to this update * @param boolean TRUE to not change the edit date of this anchor, default is FALSE */ function touch($action, $origin = NULL, $silently = FALSE) { global $context; // we make extensive use of comments below include_once $context['path_to_root'] . 'comments/comments.php'; // don't go further on import if (preg_match('/import$/i', $action)) { return; } // no article bound if (!isset($this->item['id'])) { return; } // delegate to overlay if (is_object($this->overlay) && $this->overlay->touch($action, $origin, $silently) === false) { return; // stop on false } // clear floating objects if ($action == 'clear') { $this->item['description'] .= ' [clear]'; $query = "UPDATE " . SQL::table_name('articles') . " SET description='" . SQL::escape($this->item['description']) . "'" . " WHERE id = " . SQL::escape($this->item['id']); SQL::query($query); return; } // get the related overlay, if any if (!isset($this->overlay)) { $this->overlay = NULL; if (isset($this->item['overlay'])) { $this->overlay = Overlay::load($this->item, 'article:' . $this->item['id']); } } // components of the query $query = array(); // a new comment has been posted if ($action == 'comment:create') { // purge oldest comments Comments::purge_for_anchor('article:' . $this->item['id']); // file upload } elseif ($action == 'file:create' || $action == 'file:upload') { // actually, several files have been added $label = ''; if (!$origin) { // only when comments are allowed if (!Articles::has_option('no_comments', $this->anchor, $this->item)) { // remember this as an automatic notification $fields = array(); $fields['anchor'] = 'article:' . $this->item['id']; $fields['description'] = i18n::s('Several files have been added'); $fields['type'] = 'notification'; Comments::post($fields); } // one file has been added } elseif (!Codes::check_embedded($this->item['description'], 'embed', $origin) && ($item = Files::get($origin, TRUE))) { // this file is eligible for being embedded in the page if (isset($item['file_name']) && Files::is_embeddable($item['file_name'])) { // the overlay may prevent embedding if (is_object($this->overlay) && !$this->overlay->should_embed_files()) { } else { $label = '[embed=' . $origin . ']'; } // else add a comment to take note of the upload } else { // only when comments are allowed if (!Articles::has_option('no_comments', $this->anchor, $this->item)) { // remember this as an automatic notification $fields = array(); $fields['anchor'] = 'article:' . $this->item['id']; if ($action == 'file:create') { $fields['description'] = '[file=' . $item['id'] . ',' . $item['file_name'] . ']'; } else { $fields['description'] = '[download=' . $item['id'] . ',' . $item['file_name'] . ']'; } Comments::post($fields); } } } // we are in some interactive thread if ($origin && $this->has_option('view_as_chat')) { // default is to download the file if (!$label) { $label = '[download=' . $origin . ']'; } // this is the first contribution to the thread if (!($comment = Comments::get_newest_for_anchor('article:' . $this->item['id']))) { $fields = array(); $fields['anchor'] = 'article:' . $this->item['id']; $fields['description'] = $label; // this is a continuated contribution from this authenticated surfer } elseif ($comment['type'] != 'notification' && Surfer::get_id() && (isset($comment['create_id']) && Surfer::get_id() == $comment['create_id'])) { $comment['description'] .= BR . $label; $fields = $comment; // else process the contribution as a new comment } else { $fields = array(); $fields['anchor'] = 'article:' . $this->item['id']; $fields['description'] = $label; } // only when comments are allowed if (!Articles::has_option('no_comments', $this->anchor, $this->item)) { Comments::post($fields); } // include flash videos in a regular page } elseif ($origin && $label) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' ' . $label) . "'"; } // suppress references to a deleted file } elseif ($action == 'file:delete' && $origin) { // suppress reference in main description field $text = Codes::delete_embedded($this->item['description'], 'download', $origin); $text = Codes::delete_embedded($text, 'embed', $origin); $text = Codes::delete_embedded($text, 'file', $origin); // save changes $query[] = "description = '" . SQL::escape($text) . "'"; // append a reference to a new image to the description } elseif ($action == 'image:create' && $origin) { if (!Codes::check_embedded($this->item['description'], 'image', $origin)) { // the overlay may prevent embedding if (is_object($this->overlay) && !$this->overlay->should_embed_files()) { } else { // list has already started if (preg_match('/\\[image=[^\\]]+?\\]\\s*$/', $this->item['description'])) { $this->item['description'] .= ' [image=' . $origin . ']'; } else { $this->item['description'] .= "\n\n" . '[image=' . $origin . ']'; } $query[] = "description = '" . SQL::escape($this->item['description']) . "'"; } } // also use it as thumnail if none has been defined yet if (!isset($this->item['thumbnail_url']) || !trim($this->item['thumbnail_url'])) { include_once $context['path_to_root'] . 'images/images.php'; if (($image = Images::get($origin)) && ($url = Images::get_thumbnail_href($image))) { $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } } // refresh stamp only if image update occurs within 6 hours after last edition if (SQL::strtotime($this->item['edit_date']) + 6 * 60 * 60 < time()) { $silently = TRUE; } // suppress a reference to an image that has been deleted } elseif ($action == 'image:delete' && $origin) { // suppress reference in main description field $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'image', $origin)) . "'"; // suppress references as icon and thumbnail as well include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { if ($url = Images::get_icon_href($image)) { if ($this->item['icon_url'] == $url) { $query[] = "icon_url = ''"; } if ($this->item['thumbnail_url'] == $url) { $query[] = "thumbnail_url = ''"; } } if ($url = Images::get_thumbnail_href($image)) { if ($this->item['icon_url'] == $url) { $query[] = "icon_url = ''"; } if ($this->item['thumbnail_url'] == $url) { $query[] = "thumbnail_url = ''"; } } } // set an existing image as the article icon } elseif ($action == 'image:set_as_icon' && $origin) { include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { if ($url = Images::get_icon_href($image)) { $query[] = "icon_url = '" . SQL::escape($url) . "'"; } // also use it as thumnail if none has been defined yet if (!(isset($this->item['thumbnail_url']) && trim($this->item['thumbnail_url'])) && ($url = Images::get_thumbnail_href($image))) { $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } } // set an existing image as the article thumbnail } elseif ($action == 'image:set_as_thumbnail' && $origin) { include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { // use the thumbnail for large files, or the image itself for smaller files if ($image['image_size'] > $context['thumbnail_threshold']) { $url = Images::get_thumbnail_href($image); } else { $url = Images::get_icon_href($image); } $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } elseif ($origin) { $query[] = "thumbnail_url = '" . SQL::escape($origin) . "'"; } // do not remember minor changes $silently = TRUE; // append a new image, and set it as the article thumbnail } elseif ($action == 'image:set_as_both' && $origin) { if (!Codes::check_embedded($this->item['description'], 'image', $origin)) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' [image=' . $origin . ']') . "'"; } include_once $context['path_to_root'] . 'images/images.php'; if ($image = Images::get($origin)) { // use the thumbnail for large files, or the image itself for smaller files if ($image['image_size'] > $context['thumbnail_threshold']) { $url = Images::get_thumbnail_href($image); } else { $url = Images::get_icon_href($image); } $query[] = "thumbnail_url = '" . SQL::escape($url) . "'"; } elseif ($origin) { $query[] = "thumbnail_url = '" . SQL::escape($origin) . "'"; } // do not remember minor changes $silently = TRUE; // add a reference to a location in the article description } elseif ($action == 'location:create' && $origin) { if (!Codes::check_embedded($this->item['description'], 'location', $origin)) { $query[] = "description = '" . SQL::escape($this->item['description'] . ' [location=' . $origin . ']') . "'"; } // suppress a reference to a location that has been deleted } elseif ($action == 'location:delete' && $origin) { $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'location', $origin)) . "'"; // add a reference to a new table in the article description } elseif ($action == 'table:create' && $origin) { if (!Codes::check_embedded($this->item['description'], 'table', $origin)) { $query[] = "description = '" . SQL::escape($this->item['description'] . "\n" . '[table=' . $origin . ']' . "\n") . "'"; } // suppress a reference to a table that has been deleted } elseif ($action == 'table:delete' && $origin) { $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'table', $origin)) . "'"; } // stamp the update if (!$silently) { $query[] = "edit_name='" . SQL::escape(Surfer::get_name()) . "'," . "edit_id=" . SQL::escape(Surfer::get_id()) . "," . "edit_address='" . SQL::escape(Surfer::get_email_address()) . "'," . "edit_action='" . SQL::escape($action) . "'," . "edit_date='" . gmstrftime('%Y-%m-%d %H:%M:%S') . "'"; } // update the database if (count($query)) { $query = "UPDATE " . SQL::table_name('articles') . " SET " . implode(', ', $query) . " WHERE id = " . SQL::escape($this->item['id']); SQL::query($query); } // add this page to the watch list of the contributor, on any action if (Surfer::get_id()) { Members::assign('article:' . $this->item['id'], 'user:'******'article:' . $this->item['id'], $this->item['active']); // always clear the cache, even on no update Articles::clear($this->item); // get the parent if (!$this->anchor) { $this->anchor = Anchors::get($this->item['anchor']); } // propagate the touch upwards if (is_object($this->anchor)) { $this->anchor->touch('article:update', $this->item['id'], TRUE); } }
/** * remember a version * * Save previous version of some object in the database. * It is recommended to call Versions::are_different() before calling Versions::save(), to * ensure that some change has taken place. * This function populates the error context, where applicable. * * @param array an array of fields * @param string the anchor attached to this version * @return the id of the new version, or FALSE on error * * @see versions/edit.php **/ public static function save($fields, $anchor) { global $context; // anchor cannot be empty if (!isset($anchor) || !$anchor) { Logger::error(i18n::s('No anchor has been found.')); return FALSE; } // pack arrays, etc. $content = serialize($fields); // save database space if (strlen($content) > 128 && is_callable('gzcompress')) { $content = base64_encode(gzcompress($content, 6)); } // versioning date $versioning_date = isset($fields['edit_date']) ? $fields['edit_date'] : gmstrftime('%Y-%m-%d %H:%M:%S'); // insert a new record $query = "INSERT INTO " . SQL::table_name('versions') . " SET " . "anchor='" . SQL::escape($anchor) . "'," . "content='" . SQL::escape($content) . "'," . "edit_name='" . SQL::escape(isset($fields['edit_name']) ? $fields['edit_name'] : Surfer::get_name()) . "', " . "edit_id=" . SQL::escape(isset($fields['edit_id']) ? $fields['edit_id'] : Surfer::get_id()) . ", " . "edit_address='" . SQL::escape(isset($fields['edit_address']) ? $fields['edit_address'] : Surfer::get_email_address()) . "', " . "edit_date='" . SQL::escape($versioning_date) . "'"; // actual insert if (SQL::query($query) === FALSE) { return FALSE; } // remember the id of the new item $id = SQL::get_last_id($context['connection']); // clear the cache for versions; update section index as well Cache::clear(array('articles', 'versions')); // return the id of the new item return $id; }
/** * add text to the bottom of the page * * This is where video streams from OpenTok are included * * @see overlays/event.php * * @param array the hosting record, if any * @return some HTML to be inserted into the resulting page */ function &get_trailer_text($host = NULL) { global $context; // meeting is not on-going $text = ''; if ($this->attributes['status'] != 'started') { return $text; } // use services/configure.php to activate OpenTok if (!isset($context['opentok_api_key']) || !$context['opentok_api_key']) { return $text; } // no session id! if (!isset($this->attributes['session_id']) || !$this->attributes['session_id']) { Logger::error(sprintf('OpenTok error: %s', 'no session id has been found')); return $text; } // prepare the authentication token $credentials = 'session_id=' . $this->attributes['session_id'] . '&create_time=' . time() . '&role=publisher' . '&nonce=' . microtime(true) . mt_rand(); // hash credentials using secret $hash = hash_hmac('sha1', $credentials, $context['opentok_api_secret']); // finalize the authentication token expected by OpenTok $token = 'T1==' . base64_encode('partner_id=' . $context['opentok_api_key'] . '&sig=' . $hash . ':' . $credentials); // delegate audio processing to OpenTok too $with_audio = 'true'; // except if twilio has been activated instead if (isset($context['twilio_account_sid']) && $context['twilio_account_sid']) { $with_audio = 'false'; } // load the OpenTok javascript library in shared/global.php $context['javascript']['opentok'] = TRUE; // interface with the OpenTok API $js_script = 'var OpenTok = {' . "\n" . "\n" . ' apiKey: ' . $context['opentok_api_key'] . ',' . "\n" . ' sessionId: "' . $this->attributes['session_id'] . '",' . "\n" . ' tokenString: "' . $token . '",' . "\n" . "\n" . ' deviceManager: null,' . "\n" . ' publisher: null,' . "\n" . ' session: null,' . "\n" . ' subscribers: {},' . "\n" . ' tentatives: 3,' . "\n" . ' watchdog: null,' . "\n" . ' withAudio: ' . $with_audio . ',' . "\n" . "\n" . ' // user has denied access to the camera from Flash' . "\n" . ' accessDeniedHandler: function() {' . "\n" . ' $("#opentok .me").empty();' . "\n" . ' },' . "\n" . "\n" . ' // attempt to reconnect to the server' . "\n" . ' connectAgain: function() {' . "\n" . ' OpenTok.growl("' . i18n::s('Connecting again to OpenTok') . '");' . "\n" . ' OpenTok.session.connect(OpenTok.apiKey, OpenTok.tokenString);' . "\n" . ' },' . "\n" . "\n" . ' // successful detection of local devices' . "\n" . ' devicesDetectedHandler: function(event) {' . "\n" . "\n" . ' // no adequate hardware to move forward' . "\n" . ' if(event.cameras.length == 0) {' . "\n" . ' OpenTok.growl("' . i18n::s('A webcam is required to be visible') . '");' . "\n" . "\n" . ' // at least one camera is available' . "\n" . ' } else {' . "\n" . "\n" . ' // create one placeholder div for my own camera' . "\n" . ' OpenTok.growl("' . i18n::s('Adding local video stream') . '");' . "\n" . ' $("#opentok .me").append(\'<div class="frame subscriber"><div id="placeholder"></div></div>\');' . "\n" . "\n" . ' // bind this div with my own camera' . "\n" . ' var streamProps = {width: 120, height: 90,' . "\n" . ' publishAudio: false, publishVideo: true, name: "' . str_replace('"', "'", Surfer::get_name()) . '" };' . "\n" . ' OpenTok.publisher = OpenTok.session.publish("placeholder", streamProps);' . "\n" . "\n" . ' // monitor the publishing session' . "\n" . ' OpenTok.publisher.addEventListener("accessDenied", OpenTok.accessDeniedHandler);' . "\n" . ' OpenTok.publisher.addEventListener("deviceInactive", OpenTok.deviceInactiveHandler);' . "\n" . "\n" . ' }' . "\n" . "\n" . ' },' . "\n" . "\n" . ' // for some reason the user is not publishing anymore' . "\n" . ' deviceInactiveHandler: function(event) {' . "\n" . ' if(event.camera) {' . "\n" . ' OpenTok.growl("' . i18n::s('You are not visible') . '");' . "\n" . ' }' . "\n" . ' if(event.microphone) {' . "\n" . ' OpenTok.growl("' . i18n::s('You have been muted') . '");' . "\n" . ' $("#opentok .me .frame").removeClass("talker");' . "\n" . ' }' . "\n" . ' },' . "\n" . "\n" . ' // we have been killed by an asynchronous exception' . "\n" . ' exceptionHandler: function(event) {' . "\n" . "\n" . ' OpenTok.growl(event.code + " " + event.title + " - " + event.message);' . "\n" . "\n" . ' OpenTok.tentatives--;' . "\n" . ' if((OpenTok.tentatives > 0) && (event.code === 1006 || event.code === 1008 || event.code === 1014)) {' . "\n" . ' OpenTok.session.connecting = false;' . "\n" . ' window.setTimeout("OpenTok.connectAgain()", 3000);' . "\n" . ' }' . "\n" . ' },' . "\n" . "\n" . ' // display a message for some seconds' . "\n" . ' growl: function(message) {' . "\n" . ' if(typeof OpenTok.growlId != "number") {' . "\n" . ' OpenTok.growlId = 1;' . "\n" . ' } else {' . "\n" . ' OpenTok.growlId++;' . "\n" . ' }' . "\n" . ' var myId = OpenTok.growlId++;' . "\n" . ' $("#opentok .growl").append(\'<span id="growl\'+myId+\'">\'+message+"</span>");' . "\n" . ' window.setTimeout("$(\'#growl"+myId+"\').fadeOut(\'slow\')", 5000);' . "\n" . ' },' . "\n" . "\n" . ' // launch the video chat based on OpenTok' . "\n" . ' initialize: function() {' . "\n" . "\n" . ' // report on error, if any' . "\n" . ' TB.setLogLevel(TB.DEBUG);' . "\n" . ' TB.addEventListener("exception", OpenTok.exceptionHandler);' . "\n" . "\n" . ' // check system capabilities before activating the service' . "\n" . ' if(TB.checkSystemRequirements() == TB.HAS_REQUIREMENTS) {' . "\n" . "\n" . ' // slide to page bottom, because this is not obvious to end-user' . "\n" . ' OpenTok.growl("' . i18n::s('Connecting to OpenTok') . '");' . "\n" . "\n" . ' // bind to local hardware via a device manager' . "\n" . ' OpenTok.deviceManager = TB.initDeviceManager(OpenTok.apiKey);' . "\n" . ' OpenTok.deviceManager.addEventListener("devicesDetected", OpenTok.devicesDetectedHandler);' . "\n" . "\n" . ' // bind to the API via a session' . "\n" . ' OpenTok.session = TB.initSession(OpenTok.sessionId);' . "\n" . ' OpenTok.session.addEventListener("sessionConnected", OpenTok.sessionConnectedHandler);' . "\n" . ' OpenTok.session.addEventListener("signalReceived", OpenTok.signalReceivedHandler);' . "\n" . ' OpenTok.session.addEventListener("streamCreated", OpenTok.streamCreatedHandler);' . "\n" . ' OpenTok.session.addEventListener("streamDestroyed", OpenTok.streamDestroyedHandler);' . "\n" . ' OpenTok.session.addEventListener("streamPropertyChanged", OpenTok.streamPropertyChangedHandler);' . "\n" . "\n" . ' // connect to back-end servers' . "\n" . ' OpenTok.session.connect(OpenTok.apiKey, OpenTok.tokenString);' . "\n" . "\n" . ' // no way to use the service' . "\n" . ' } else {' . "\n" . ' OpenTok.growl("' . i18n::s('This system is not supported by OpenTok') . '");' . "\n" . ' }' . "\n" . ' },' . "\n" . "\n" . ' // successful connection to the OpenTok back-end servers' . "\n" . ' sessionConnectedHandler: function(event) {' . "\n" . "\n" . ' // display streams already attached to this session' . "\n" . ' OpenTok.subscribeToStreams(event.streams);' . "\n" . "\n" . ' // attach the local webcam and microphone if detected' . "\n" . ' OpenTok.deviceManager.detectDevices();' . "\n" . ' },' . "\n" . "\n" . ' // send a signal to other parties' . "\n" . ' signal: function() {' . "\n" . ' if(OpenTok.session)' . "\n" . ' OpenTok.session.signal();' . "\n" . ' },' . "\n" . "\n" . ' // signal received, refresh the page' . "\n" . ' signalReceivedHandler: function(event) {' . "\n" . "\n" . ' // refresh the chat area' . "\n" . ' if(typeof Comments == "object")' . "\n" . ' Comments.subscribe();' . "\n" . ' },' . "\n" . "\n" . ' // i start to talk' . "\n" . ' startTalking: function() {' . "\n" . ' for(var i = 0; i < OpenTok.subscribers.length; i++) {' . "\n" . ' OpenTok.subscribers[i].subscribeToAudio(false);' . "\n" . ' }' . "\n" . ' OpenTok.publisher.publishAudio(true);' . "\n" . "\n" . ' document.getElementById("pushToTalk").onclick = OpenTok.stopTalking;' . "\n" . ' document.getElementById("pushToTalk").value = "' . i18n::s('Stop talking') . '";' . "\n"; // identify the chairman or, if unknown, the owner of this page $chairman = array(); if (isset($this->attributes['chairman']) && $this->attributes['chairman']) { $chairman = Users::get($this->attributes['chairman']); } if (!isset($chairman['id']) && ($owner = $this->anchor->get_value('owner_id'))) { $chairman = Users::get($owner); } // if this surfer is the chairman of this meeting, he will take over after three seconds of silence if (isset($chairman['id']) && Surfer::is($chairman['id'])) { $js_script .= 'OpenTok.watchdog = setInterval(function () {' . 'if(!$("#opentok .talker").length) {OpenTok.startTalking();}' . '}, 3000);' . "\n"; } // end of javascript snippet $js_script .= ' },' . "\n" . "\n" . ' // i am back to listening mode' . "\n" . ' stopTalking: function() {' . "\n" . ' if(OpenTok.watchdog) { clearInterval(OpenTok.watchdog); OpenTok.watchdog = null; }' . "\n" . ' OpenTok.publisher.publishAudio(false);' . "\n" . ' for(var i = 0; i < OpenTok.subscribers.length; i++) {' . "\n" . ' OpenTok.subscribers[i].subscribeToAudio(true);' . "\n" . ' }' . "\n" . "\n" . ' document.getElementById("pushToTalk").onclick = OpenTok.startTalking;' . "\n" . ' document.getElementById("pushToTalk").value = "' . i18n::s('Start talking') . '";' . "\n" . ' },' . "\n" . "\n" . ' // display new streams on people arrival' . "\n" . ' streamCreatedHandler: function(event) {' . "\n" . ' OpenTok.subscribeToStreams(event.streams);' . "\n" . ' },' . "\n" . "\n" . ' // remove a stream that has been destroyed' . "\n" . ' streamDestroyedHandler: function(event) {' . "\n" . ' for(i = 0; i < event.streams.length; i++) {' . "\n" . ' var stream = event.streams[i];' . "\n" . ' $("#opentok_"+stream.streamId).remove();' . "\n" . ' }' . "\n" . ' },' . "\n" . "\n" . ' // a stream has started or stopped' . "\n" . ' streamPropertyChangedHandler: function(event) {' . "\n" . ' switch(event.changedProperty) {' . "\n" . ' case "hasAudio":' . "\n" . ' if(event.newValue) {' . "\n" . ' OpenTok.growl("' . i18n::s("%s is talking") . '".replace(/%s/, event.stream.name));' . "\n" . ' if(event.stream.connection.connectionId != OpenTok.session.connection.connectionId) {' . "\n" . ' $("#opentok_"+event.stream.streamId).addClass("talker");' . "\n" . ' OpenTok.stopTalking();' . "\n" . ' } else {' . "\n" . ' $("#opentok .me .frame").addClass("talker");' . "\n" . ' }' . "\n" . ' } else {' . "\n" . ' OpenTok.growl("' . i18n::s("%s is listening") . '".replace(/%s/, event.stream.name));' . "\n" . ' if(event.stream.connection.connectionId != OpenTok.session.connection.connectionId) {' . "\n" . ' $("#opentok_"+event.stream.streamId).removeClass("talker");' . "\n" . ' } else {' . "\n" . ' $("#opentok .me .frame").removeClass("talker");' . "\n" . ' }' . "\n" . ' }' . "\n" . ' break;' . "\n" . ' case "hasVideo":' . "\n" . ' if(!event.newValue) {' . "\n" . ' OpenTok.growl("' . i18n::s("%s is not visible") . '".replace(/%s/, event.stream.name));' . "\n" . ' }' . "\n" . ' break;' . "\n" . ' }' . "\n" . ' },' . "\n" . "\n" . ' // add new streams to the user interface' . "\n" . ' subscribeToStreams: function(streams) {' . "\n" . "\n" . ' // some remote stream in the list?' . "\n" . ' for(i = 0; i < streams.length; i++) {' . "\n" . ' if(streams[i].connection.connectionId != OpenTok.session.connection.connectionId) {' . "\n" . ' OpenTok.growl("' . i18n::s('Adding remote video streams') . '");' . "\n" . ' break;' . "\n" . ' }' . "\n" . ' }' . "\n" . "\n" . ' for(i = 0; i < streams.length; i++) {' . "\n" . ' var stream = streams[i];' . "\n" . "\n" . ' // subscribe to all streams, except my own camera' . "\n" . ' if(stream.connection.connectionId != OpenTok.session.connection.connectionId) {' . "\n" . "\n" . ' // create one div per subscribed stream and give it the id of the stream' . "\n" . ' $("#opentok .others").append(\'<span id="opentok_\'+stream.streamId+\'"><span id="placeholder"></span></span>\');' . "\n" . ' $("#opentok_"+stream.streamId).addClass("ibox subscriber").css({width: 120, height: 90 });' . "\n" . "\n" . ' // bind the stream to this div' . "\n" . ' var streamProps = {width: 120, height: 90, subscribeToAudio: true, subscribeToVideo: true};' . "\n" . ' OpenTok.subscribers[stream.streamId] = OpenTok.session.subscribe(stream, "placeholder", streamProps);' . "\n" . "\n" . ' // the remote stream is active' . "\n" . ' if(stream.hasAudio) {' . "\n" . ' OpenTok.growl("' . i18n::s("%s is talking") . '".replace(/%s/, stream.name));' . "\n" . ' $("#opentok_"+stream.streamId).addClass("talker");' . "\n" . ' }' . "\n" . "\n" . ' // the default is to push to talk' . "\n" . ' } else if(OpenTok.withAudio) {' . "\n" . ' $("#opentok .me").append(\'<div style="text-align: center; padding: 2px 0;">' . '<input type="button" id="pushToTalk" value="' . i18n::s('Start talking') . '" onClick="OpenTok.startTalking()" />' . '</div>\');' . "\n" . ' OpenTok.growl("' . i18n::s("Click on the button before talking") . '");' . "\n" . ' }' . "\n" . ' }' . "\n" . ' $("#opentok .me .frame").addClass("subscriber").css({width: 120, height: 90});' . "\n" . ' $("#description").focus();' . "\n" . ' }' . "\n" . "\n" . '}' . "\n" . "\n" . '// bind to OpenTok' . "\n" . '$(document).ready(OpenTok.initialize);' . "\n" . "\n"; Page::insert_script($js_script); // video streams are put above the chat area $text = '<div id="opentok">' . '<div class="growl" style="height: 1.6em;" > </div>' . '<table class="layout"><tr>' . '<td class="me"></td>' . '<td class="others"></td>' . '</tr></table>' . '</div>' . "\n"; return $text; }
$local['title_fr'] = 'Appuyer sur [s] pour enregistrer les données'; $menu[] = Skin::build_submit_button(i18n::user('submit'), i18n::user('title'), 's'); // control panel $menu[] = Skin::build_link('control/', i18n::user('Control Panel'), 'span'); // insert the menu in the page $context['text'] .= Skin::finalize_list($menu, 'assistant_bar'); // end of the form $context['text'] .= '</form>'; // no modifications in demo mode } elseif (file_exists($context['path_to_root'] . 'parameters/demo.flag')) { Safe::header('Status: 401 Unauthorized', TRUE, 401); Logger::error(i18n::s('You are not allowed to perform this operation.')); // save updated parameters } else { // build the new configuration file $content = '<?php' . "\n" . '// This file has been created by the configuration script overlays/bbb_meetings/configure.php' . "\n" . '// on ' . gmdate("F j, Y, g:i a") . ' GMT, for ' . Surfer::get_name() . '. Please do not modify it manually.' . "\n"; if (isset($_REQUEST['bbb_server'])) { $content .= '$context[\'bbb_server\']=\'' . addcslashes($_REQUEST['bbb_server'], "\\'") . "';\n"; } if (isset($_REQUEST['bbb_salt'])) { $content .= '$context[\'bbb_salt\']=\'' . addcslashes($_REQUEST['bbb_salt'], "\\'") . "';\n"; } $content .= '?>' . "\n"; // update the parameters file if (!Safe::file_put_contents('parameters/overlays.bbb_meetings.include.php', $content)) { Logger::error(sprintf(i18n::s('ERROR: Impossible to write to the file %s. The configuration has not been saved.'), 'parameters/overlays.bbb_meetings.include.php')); // report to end-user } else { $context['text'] .= '<p>' . sprintf(i18n::s('The following configuration has been saved into the file %s.'), 'parameters/overlays.bbb_meetings.include.php') . "</p>\n"; // purge the cache Cache::clear();
// clear assignment information if (Files::assign($item['id'], NULL)) { // inform surfer $context['text'] .= '<p>' . i18n::s('You have released this file, and other surfers can reserve it for revision.') . '</p>'; // help the surfer } else { Logger::error(i18n::s('Operation has failed.')); } // follow-up commands $context['text'] .= Skin::build_block(Skin::build_link($anchor->get_url('files'), i18n::s('Done'), 'button'), 'bottom'); // file has not been assigned, and surfer has not confirmed the detach yet } elseif ($action == 'reserve' && (!isset($item['assign_id']) || !$item['assign_id']) && Surfer::get_id()) { // change page title $context['page_title'] = sprintf(i18n::s('%s: %s'), i18n::s('Reserve'), $context['page_title']); // assign the file to this surfer $user = array('nick_name' => Surfer::get_name(), 'id' => Surfer::get_id(), 'email' => Surfer::get_email_address()); if (Files::assign($item['id'], $user)) { // inform surfer $context['text'] .= '<p>' . sprintf(i18n::s('You have reserved this file, and you are encouraged to %s as soon as possible, or to %s.'), Skin::build_link(Files::get_url($item['id'], 'edit'), i18n::s('upload an updated version'), 'basic'), Skin::build_link(Files::get_url($item['id'], 'fetch', 'release'), i18n::s('release reservation'), 'basic')) . '</p>'; // help the surfer } else { Logger::error(i18n::s('Operation has failed.')); } // follow-up commands $context['text'] .= Skin::build_block(Skin::build_link($anchor->get_url('files'), i18n::s('Done'), 'button'), 'bottom'); // file has been reserved, and surfer is not owner } elseif ($action != 'confirm' && isset($item['assign_id']) && $item['assign_id'] && !Surfer::is($item['assign_id'])) { // inform surfer $context['text'] .= Skin::build_block(sprintf(i18n::s('This file has been assigned to %s %s, and it is likely that an updated version will be made available soon.'), Users::get_link($item['assign_name'], $item['assign_address'], $item['assign_id']), Skin::build_date($item['assign_date'])), 'caution'); // commands $menu = array();
$menu = array_merge($menu, array($article->get_url() => i18n::s('View the page'))); $menu = array_merge($menu, array($article->get_url('edit') => i18n::s('Edit the page'))); if (Surfer::may_upload()) { $menu = array_merge($menu, array('images/edit.php?anchor=' . urlencode($article->get_reference()) => i18n::s('Add an image'))); $menu = array_merge($menu, array('files/edit.php?anchor=' . urlencode($article->get_reference()) => i18n::s('Add a file'))); } $menu = array_merge($menu, array('links/edit.php?anchor=' . urlencode($article->get_reference()) => i18n::s('Add a link'))); $follow_up .= Skin::build_list($menu, 'menu_bar'); $context['text'] .= Skin::build_block($follow_up, 'bottom'); // log the creation of a new article $label = sprintf(i18n::c('Article copy: %s'), strip_tags($article->get_title())); // poster and target section if (is_object($anchor)) { $description = sprintf(i18n::c('Sent by %s in %s'), Surfer::get_name(), $anchor->get_title()); } else { $description = sprintf(i18n::c('Sent by %s'), Surfer::get_name()); } // title and link if ($title = $article->get_title()) { $description .= $title . "\n"; } $description = '<a href="' . $context['url_to_home'] . $context['url_to_root'] . $article->get_url() . '">' . $article->get_title() . '</a>'; // notify sysops Logger::notify('articles/duplicate.php: ' . $label, $description); } // action has to be confirmed } elseif (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST') { Logger::error(i18n::s('The action has not been confirmed.')); // please confirm } else { // the article or the anchor icon, if any
Logger::notify('query.php: ' . $label, $description); } } // display the form on GET } else { $with_form = TRUE; } // display the form if ($with_form) { // splash message $context['text'] .= '<p>' . i18n::s('Please fill out the form and it will be sent automatically to the site managers. Be as precise as possible, and mention your e-mail address to let us a chance to contact you back.') . "</p>\n"; // the form to send a query $context['text'] .= '<form method="post" action="' . $context['script_url'] . '" onsubmit="return validateDocumentPost(this)" id="main_form"><div>'; // surfer name if (!isset($item['edit_name'])) { $item['edit_name'] = Surfer::get_name(); } $label = i18n::s('Your name') . ' *'; $input = '<input type="text" name="edit_name" id="edit_name" size="45" value="' . encode_field($item['edit_name']) . '" maxlength="255" />'; $hint = i18n::s('Let us a chance to know who you are'); $fields[] = array($label, $input, $hint); // surfer address if (!isset($item['edit_address'])) { $item['edit_address'] = Surfer::get_email_address(); } $label = i18n::s('Your e-mail address') . ' *'; $input = '<input type="text" name="edit_address" size="45" value="' . encode_field($item['edit_address']) . '" maxlength="255" />'; $hint = i18n::s('To be alerted during the processing of your request'); $fields[] = array($label, $input, $hint); // stop robots if ($field = Surfer::get_robot_stopper()) {
/** * build a notification related to a section * * This function builds a mail message that displays: * - an image of the contributor (if possible) * - a headline mentioning the contribution * - the full content of the section * - a button linked to the section * - a link to the containing section, if any * * Note: this function returns legacy HTML, not modern XHTML, because this is what most * e-mail client software can afford. * * @param string either 'apply', 'create' or 'update' * @param array attributes of the item * @param object overlay of the item, if any * @return string text to be send by e-mail */ public static function build_notification($action, $item, $overlay = NULL) { global $context; // get the main anchor $anchor = Anchors::get($item['anchor']); // compute page title if (is_object($overlay)) { $title = Codes::beautify_title($overlay->get_text('title', $item)); } else { $title = Codes::beautify_title($item['title']); } // headline template switch ($action) { case 'apply': $template = i18n::c('%s is requesting access to %s'); break; case 'create': $template = i18n::c('%s has created section %s'); break; case 'update': $template = i18n::c('%s has updated section %s'); break; } // headline $headline = sprintf($template, Surfer::get_link(), '<a href="' . Sections::get_permalink($item) . '">' . $title . '</a>'); // panel content $content = ''; // signal restricted and private articles if ($item['active'] == 'N') { $title = PRIVATE_FLAG . $title; } elseif ($item['active'] == 'R') { $title = RESTRICTED_FLAG . $title; } // insert page title $content .= '<h3><span>' . $title . '</span></h3>'; // insert anchor prefix if (is_object($anchor)) { $content .= $anchor->get_prefix(); } // the introduction text, if any if (is_object($overlay)) { $content .= Skin::build_block($overlay->get_text('introduction', $item), 'introduction'); } elseif (isset($item['introduction']) && trim($item['introduction'])) { $content .= Skin::build_block($item['introduction'], 'introduction'); } // get text related to the overlay, if any if (is_object($overlay)) { $content .= $overlay->get_text('view', $item); } // filter description, if necessary if (is_object($overlay)) { $description = $overlay->get_text('description', $item); } else { $description = $item['description']; } // the beautified description, which is the actual page body if ($description) { // use adequate label if (is_object($overlay) && ($label = $overlay->get_label('description'))) { $content .= Skin::build_block($label, 'title'); } // beautify the target page $content .= Skin::build_block($description, 'description', '', $item['options']); } // attachment details $details = array(); // info on related sections if ($count = Sections::count_for_anchor('section:' . $item['id'])) { $details[] = sprintf(i18n::nc('%d section', '%d sections', $count), $count); } // info on related articles if ($count = Articles::count_for_anchor('section:' . $item['id'])) { $details[] = sprintf(i18n::nc('%d page', '%d pages', $count), $count); } // info on related files if ($count = Files::count_for_anchor('section:' . $item['id'], TRUE)) { // the actual list of files attached to this section if (preg_match('/\\bfiles_by_title\\b/i', $item['options'])) { $items = Files::list_by_title_for_anchor('section:' . $item['id'], 0, 300, 'compact'); } else { $items = Files::list_by_date_for_anchor('section:' . $item['id'], 0, 300, 'compact'); } // wrap it with some header if (is_array($items)) { $items = Skin::build_list($items); } if ($items) { $content .= '<h3><span>' . i18n::s('Files') . '</span></h3>' . $items; } // details to be displayed at page bottom $details[] = sprintf(i18n::nc('%d file', '%d files', $count), $count); } // info on related links include_once $context['path_to_root'] . 'links/links.php'; if ($count = Links::count_for_anchor('section:' . $item['id'], TRUE)) { $details[] = sprintf(i18n::nc('%d link', '%d links', $count), $count); } // comments include_once $context['path_to_root'] . 'comments/comments.php'; if ($count = Comments::count_for_anchor('section:' . $item['id'], TRUE)) { $details[] = sprintf(i18n::nc('%d comment', '%d comments', $count), $count); } // describe attachments if (count($details)) { $content .= '<hr align="left" size=1" width="150">' . '<p style="margin: 3px 0;">' . sprintf(i18n::c('This section has %s'), join(', ', $details)) . '</p>'; } // assemble main content of this message $text = Skin::build_mail_content($headline, $content); // a set of links $menu = array(); // request access to the item if ($action == 'apply') { // call for action $link = $context['url_to_home'] . $context['url_to_root'] . Sections::get_url($item['id'], 'invite', Surfer::get_id()); $label = sprintf(i18n::c('Invite %s to participate'), Surfer::get_name()); $menu[] = Skin::build_mail_button($link, $label, TRUE); // link to user profile $link = Surfer::get_permalink(); $label = sprintf(i18n::c('View the profile of %s'), Surfer::get_name()); $menu[] = Skin::build_mail_button($link, $label, FALSE); // invite to visit the item } else { // call for action $link = Sections::get_permalink($item); if (!is_object($overlay) || !($label = $overlay->get_label('permalink_command', 'sections', FALSE))) { $label = i18n::c('View the section'); } $menu[] = Skin::build_mail_button($link, $label, TRUE); // link to the container if (is_object($anchor)) { $link = $context['url_to_home'] . $context['url_to_root'] . $anchor->get_url(); $menu[] = Skin::build_mail_button($link, $anchor->get_title(), FALSE); } } // finalize links $text .= Skin::build_mail_menu($menu); // the full message return $text; }
// $text = ''; // additional fields for anonymous surfers if (!Surfer::is_logged()) { // splash if (isset($item['id'])) { $login_url = $context['url_to_root'] . 'users/login.php?url=' . urlencode('articles/edit.php?id=' . $item['id']); } elseif (is_object($anchor)) { $login_url = $context['url_to_root'] . 'users/login.php?url=' . urlencode('articles/edit.php?anchor=' . $anchor->get_reference()); } else { $login_url = $context['url_to_root'] . 'users/login.php?url=' . urlencode('articles/edit.php'); } $text .= '<p>' . sprintf(i18n::s('If you have previously registered to this site, please %s. Then the server will automatically put your name and address in following fields.'), Skin::build_link($login_url, 'authenticate')) . "</p>\n"; // the name, if any $label = i18n::s('Your name'); $input = '<input type="text" name="edit_name" size="45" maxlength="128" accesskey="n" value="' . encode_field(Surfer::get_name(' ')) . '" />'; $hint = i18n::s('Let us a chance to know who you are'); $fields[] = array($label, $input, $hint); // the address, if any $label = i18n::s('Your e-mail address'); $input = '<input type="text" name="edit_address" size="45" maxlength="128" accesskey="a" value="' . encode_field(Surfer::get_email_address()) . '" />'; $hint = i18n::s('Put your e-mail address to receive feed-back'); $fields[] = array($label, $input, $hint); // stop robots if ($field = Surfer::get_robot_stopper()) { $fields[] = $field; } } // the title if (!is_object($overlay) || !($label = $overlay->get_label('title', isset($item['id']) ? 'edit' : 'new'))) { $label = i18n::s('Title') . ' *';
$context['text'] .= '</div></form>'; // set the focus Page::insert_script('$("#reference_server").focus();'); // general help on this form $help = '<p>' . i18n::s('Indicate only the DNS name or IP address of the reference server.') . '</p>'; // no modifications in demo mode } elseif (file_exists($context['path_to_root'] . 'parameters/demo.flag')) { Safe::header('Status: 401 Unauthorized', TRUE, 401); Logger::error(i18n::s('You are not allowed to perform this operation in demonstration mode.')); // save updated parameters } else { // backup the old version Safe::unlink($context['path_to_root'] . 'parameters/scripts.include.php.bak'); Safe::rename($context['path_to_root'] . 'parameters/scripts.include.php', $context['path_to_root'] . 'parameters/scripts.include.php.bak'); // build the new configuration file $content = '<?php' . "\n" . '// This file has been created by the configuration script scripts/configure.php' . "\n" . '// on ' . gmdate("F j, Y, g:i a") . ' GMT, for ' . Surfer::get_name() . '. Please do not modify it manually.' . "\n" . '$context[\'home_at_root\']=\'' . addcslashes($_REQUEST['home_at_root'], "\\'") . "';\n" . '$context[\'reference_server\']=\'' . addcslashes($_REQUEST['reference_server'], "\\'") . "';\n" . '?>' . "\n"; // update the parameters file if (!Safe::file_put_contents('parameters/scripts.include.php', $content)) { Logger::error(sprintf(i18n::s('ERROR: Impossible to write to the file %s. The configuration has not been saved.'), 'parameters/scripts.include.php')); // allow for a manual update $context['text'] .= '<p style="text-decoration: blink;">' . sprintf(i18n::s('To actually change the configuration, please copy and paste following lines by yourself in file %s.'), 'parameters/scripts.include.php') . "</p>\n"; // job done } else { $context['text'] .= '<p>' . sprintf(i18n::s('The following configuration has been saved into the file %s.'), 'parameters/scripts.include.php') . "</p>\n"; // purge the cache Cache::clear(); // remember the change $label = sprintf(i18n::c('%s has been updated'), 'parameters/scripts.include.php'); Logger::remember('scripts/configure.php: ' . $label); } // display updated parameters
/** * the URL to start and to join the meeting * * @see overlays/events/start.php * * @return string the URL to redirect the user to the meeting, or NULL on error */ function get_start_url() { global $context; // almost random passwords $this->initialize_passwords(); // parameters to create a meeting $parameters = array(); // use page id as meeting id $parameters[] = 'name=' . urlencode($this->attributes['id']); $parameters[] = 'meetingID=' . urlencode($this->attributes['id']); // surfer name, as authenticated by yacs $parameters[] = 'fullName=' . urlencode(Surfer::get_name()); // moderator password $parameters[] = 'moderatorPW=' . urlencode($this->moderator_password); // participant password $parameters[] = 'attendeePW=' . urlencode($this->attendee_password); // ensure that the bridge number fits in the dialing plan $parameters[] = 'voiceBridge=' . urlencode(substr('7' . $this->attributes['id'] . '1234', 0, 5)); // message displayed within the BigBlueButton session $welcome = ''; // meeting title if (is_object($this->anchor)) { $welcome .= sprintf(i18n::s('%s: %s'), i18n::s('Title'), $this->anchor->get_title()) . "\n"; } // meeting date if (isset($this->attributes['date_stamp'])) { $welcome .= sprintf(i18n::s('%s: %s'), i18n::s('Date'), Skin::build_date($this->attributes['date_stamp'], 'standalone')) . "\n"; } // meeting duration if (isset($this->attributes['duration'])) { $welcome .= sprintf(i18n::s('%s: %s'), i18n::s('Duration'), $this->attributes['duration'] . ' ' . i18n::s('minutes')) . "\n"; } // build a link to the owner page, if any if (is_object($this->anchor) && ($user = Users::get($this->anchor->get_value('owner_id')))) { $welcome .= sprintf(i18n::s('%s: %s'), i18n::s('Chairman'), $user['full_name']) . "\n"; } // welcome message $parameters[] = 'welcome=' . urlencode($welcome); // return URL if (is_callable(array($this->anchor, 'get_url'))) { $parameters[] = 'logoutURL=' . urlencode($context['url_to_home'] . $context['url_to_root'] . $this->anchor->get_url()); } // should we record this session? if ($this->with_session_recording()) { $parameters[] = 'record=true'; $parameters[] = 'duration=125'; // 2 hours max per recording } // link to create the meeting $url = $this->build_link('create', $parameters); // list most recent files that have been attached to this page $headers = NULL; $body = NULL; if (is_object($this->anchor) && ($files = Files::list_by_date_for_anchor($this->anchor->get_reference(), 0, 5, 'raw'))) { $headers = array("Content-Type: text/xml"); // instruct the presentation module to pre-load these files $body = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" . '<modules>' . "\n" . ' <module name="presentation">' . "\n"; // list web address of each file foreach ($files as $file) { $body .= "\t\t" . '<document' . ' url="' . $context['url_to_home'] . $context['url_to_root'] . utf8::to_xml(Files::get_url($file['id'], 'fetch', $file['file_name'])) . '"' . ' name="' . utf8::to_xml($file['file_name']) . '"' . ' />' . "\n"; } // end of the list of files $body .= ' </module>' . "\n" . '</modules>' . "\n"; } // do create the meeting if (($response = http::proceed_natively($url, $headers, $body)) && ($xml = simplexml_load_string($response)) && $xml->returncode == 'SUCCESS') { // parameters to join the meeting $parameters = array(); // use page id as meeting id $parameters[] = 'meetingID=' . urlencode($xml->meetingID); // surfer name, as authenticated by yacs $parameters[] = 'fullName=' . urlencode(Surfer::get_name()); // moderator password $parameters[] = 'password='******'join', $parameters); return $url; } // problem, darling! return NULL; }
/** * the URL to start and to join the meeting * * @see overlays/events/start.php * * @return string the URL to redirect the user to the meeting, or NULL on error */ function get_start_url() { global $context; // almost random passwords $this->initialize_passwords(); // link to authenticate $url = 'https://my.dimdim.com/api/auth/login'; // parameters to authenticate $parameters = array(); $parameters['account'] = $this->attributes['account']; $parameters['password'] = $this->attributes['password']; $parameters['group'] = 'all'; // encode in json $data = array('request' => Safe::json_encode($parameters)); // do authenticate if ($response = http::proceed($url, '', $data)) { // successful authentication $output = Safe::json_decode($response); if (isset($output['result']) && $output['result']) { // remember the authentication token $fields = array('token' => $output['response']['authToken']); $this->set_values($fields); // link to create a meeting $url = 'https://my.dimdim.com/api/conf/start_meeting'; // provide authentication token $headers = 'X-Dimdim-Auth-Token: ' . $this->attributes['token'] . CRLF; // parameters to create a meeting $parameters = array(); $parameters['authToken'] = $this->attributes['token']; $parameters['account'] = $this->attributes['account']; $parameters['clientId'] = Surfer::get_id(); $parameters['displayName'] = Surfer::get_name(); $parameters['meetingName'] = $this->anchor->get_title(); $parameters['roomName'] = $this->anchor->get_title(); $parameters['meetingLengthMinutes'] = $this->attributes['duration']; $parameters['attendeeKey'] = $this->attendee_password; $parameters['assistantEnabled'] = 'false'; // disable some features $parameters['displayDialInfo'] = 'false'; // message displayed within the BigBlueButton session $welcome = ''; // meeting title if (is_object($this->anchor)) { $welcome .= sprintf(i18n::s('%s: %s'), i18n::s('Title'), $this->anchor->get_title()) . "\n"; } // meeting date if (isset($this->attributes['date_stamp'])) { $welcome .= sprintf(i18n::s('%s: %s'), i18n::s('Date'), Skin::build_date($this->attributes['date_stamp'], 'standalone')) . "\n"; } // meeting duration if (isset($this->attributes['duration'])) { $welcome .= sprintf(i18n::s('%s: %s'), i18n::s('Duration'), $this->attributes['duration'] . ' ' . i18n::s('minutes')) . "\n"; } // build a link to the owner page, if any if (is_object($this->anchor) && ($user = Users::get($this->anchor->get_value('owner_id')))) { $welcome .= sprintf(i18n::s('%s: %s'), i18n::s('Chairman'), $user['full_name']) . "\n"; } // welcome message $parameters['agenda'] = $welcome; // return URL if (is_callable(array($this->anchor, 'get_url'))) { $parameters['returnurl'] = $context['url_to_home'] . $context['url_to_root'] . $this->anchor->get_url(); } // encode in json $data = array('request' => Safe::json_encode($parameters)); // do the transaction if ($response = http::proceed($url, $headers, $data)) { // successful transaction $output = Safe::json_decode($response); if (isset($output['result']) && $output['result']) { // redirect to the target page return 'https://my.dimdim.com/redirect?clientId=' . urlencode(Surfer::get_id()) . '&account=' . urlencode($this->attributes['account']); } } } } // don't know where to go return NULL; }
$context['text'] .= '<p>' . i18n::s('The server is currently switched on. Pages are provided normally to surfers.') . "</p>\n"; // failure } else { Logger::error(i18n::s('The server has NOT been switched on successfully. Please rename the file parameters/switch.off to parameters/switch.on.')); } // back to the control panel $menu = array('control/' => i18n::s('Control Panel')); $context['text'] .= Skin::build_list($menu, 'menu_bar'); // reset localized strings to reload those who could have changed during the update if (is_callable(array('i18n', 'reset'))) { i18n::reset(); } // switch off } elseif (isset($_REQUEST['action']) && $_REQUEST['action'] == 'off') { // build the new configuration file $content = '<?php' . "\n" . '// This file has been created by the configuration script control/switch.php' . "\n" . '// on ' . gmdate("F j, Y, g:i a") . ' GMT, for ' . Surfer::get_name() . '. Please do not modify it manually.' . "\n" . 'global $context;' . "\n"; if (isset($_REQUEST['switch_target'])) { $content .= '$context[\'switch_target\']=\'' . addcslashes($_REQUEST['switch_target'], "\\'") . "';\n"; } if (isset($_REQUEST['switch_contact'])) { $content .= '$context[\'switch_contact\']=\'' . addcslashes($_REQUEST['switch_contact'], "\\'") . "';\n"; } $content .= '?>' . "\n"; // save switch parameters, if any if (!Safe::file_put_contents('parameters/switch.include.php', $content)) { // not enough rights to write the file Logger::error(sprintf(i18n::s('Impossible to write to %s.'), 'parameters/switch.include.php.')); // allow for a manual update $context['text'] .= '<p style="text-decoration: blink;">' . sprintf(i18n::s('To actually change the configuration, please copy and paste following lines by yourself in file %s.'), 'parameters/switch.include.php') . "</p>\n"; // display updated parameters $context['text'] .= Skin::build_box(i18n::s('Configuration'), Safe::highlight_string($content), 'folded');
// display the main page content, but not the menu bar Page::content(FALSE); // end of the main panel echo '</td>' . "\n"; // the side panel is displayed on all pages; it includes the menu and other navigation boxes echo '<td id="side_panel">' . "\n"; // display side content Page::side(); // end of the navigation panel echo '</td></tr></table>' . "\n"; // the footer panel echo '<div id="footer_panel">' . "\n"; // surfer name and execution time, if known if (is_callable(array('Surfer', 'get_name')) && is_callable(array('i18n', 's'))) { $execution_time = round(get_micro_time() - $context['start_time'], 2); echo sprintf(i18n::s('Page prepared in %.2f seconds for %s'), $execution_time, ucwords(Surfer::get_name())) . ' '; } // site copyright if (isset($context['site_copyright'])) { echo '<br />Copyright © ' . $context['site_copyright'] . "\n"; } // a command to authenticate if (is_callable(array('Surfer', 'is_logged')) && !Surfer::is_logged() && is_callable(array('i18n', 's'))) { echo ' - ' . Skin::build_link('users/login.php', i18n::s('login'), 'basic') . ' '; } // about this site if (is_callable(array('i18n', 's')) && is_callable(array('Articles', 'get_url'))) { echo ' - ' . Skin::build_link(Articles::get_url('about'), i18n::s('about this site'), 'basic') . ' '; } // privacy statement if (is_callable(array('i18n', 's')) && is_callable(array('Articles', 'get_url'))) {