forked from GNUsocial/gnu-social
		
	Merge commit 'origin/0.8.x' into 0.9.x
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -23,4 +23,4 @@ config-*.php | ||||
| good-config.php | ||||
| lac08.log | ||||
| php.log | ||||
| config.php.* | ||||
|  | ||||
|   | ||||
							
								
								
									
										17
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								README
									
									
									
									
									
								
							| @@ -964,9 +964,6 @@ sslserver: use an alternate server name for SSL URLs, like | ||||
| shorturllength: Length of URL at which URLs in a message exceeding 140 | ||||
|                 characters will be sent to the user's chosen | ||||
|                 shortening service. | ||||
| design: a default design (colors and background) for the site. | ||||
|         Sub-items are: backgroundcolor, contentcolor, sidebarcolor, | ||||
|         textcolor, linkcolor, backgroundimage, disposition. | ||||
| dupelimit: minimum time allowed for one person to say the same thing | ||||
|            twice. Default 60s. Anything lower is considered a user | ||||
|            or UI error. | ||||
| @@ -1432,6 +1429,20 @@ notify third-party servers of updates. | ||||
| notify: an array of URLs for ping endpoints. Default is the empty | ||||
|         array (no notification). | ||||
|  | ||||
| design | ||||
| ------ | ||||
|  | ||||
| Default design (colors and background) for the site. Actual appearance | ||||
| depends on the theme.  Null values mean to use the theme defaults. | ||||
|  | ||||
| backgroundcolor: Hex color of the site background. | ||||
| contentcolor: Hex color of the content area background. | ||||
| sidebarcolor: Hex color of the sidebar background. | ||||
| textcolor: Hex color of all non-link text. | ||||
| linkcolor: Hex color of all links. | ||||
| backgroundimage: Image to use for the background. | ||||
| disposition: Flags for whether or not to tile the background image. | ||||
|  | ||||
| Plugins | ||||
| ======= | ||||
|  | ||||
|   | ||||
| @@ -130,6 +130,7 @@ class ApiAction extends Action | ||||
|                                 'laconica/wadl', | ||||
|                                 'tags/timeline', | ||||
|                                 'oembed/oembed', | ||||
|                                 'groups/show', | ||||
|                                 'groups/timeline'); | ||||
|  | ||||
|         static $bareauth = array('statuses/user_timeline', | ||||
|   | ||||
| @@ -167,6 +167,8 @@ class ConversationTree extends NoticeList | ||||
|  | ||||
|     function _buildTree() | ||||
|     { | ||||
|         $cnt = 0; | ||||
|  | ||||
|         $this->tree  = array(); | ||||
|         $this->table = array(); | ||||
|  | ||||
|   | ||||
| @@ -229,7 +229,7 @@ class PublicAction extends Action | ||||
|         // $top->show(); | ||||
|         $pop = new PopularNoticeSection($this); | ||||
|         $pop->show(); | ||||
|         $gbp = new GroupsByPostsSection($this); | ||||
|         $gbp = new GroupsByMembersSection($this); | ||||
|         $gbp->show(); | ||||
|         $feat = new FeaturedUsersSection($this); | ||||
|         $feat->show(); | ||||
|   | ||||
| @@ -207,32 +207,10 @@ class TwitapifavoritesAction extends TwitterapiAction | ||||
|         $other = User::staticGet('id', $notice->profile_id); | ||||
|         if ($other && $other->id != $user->id) { | ||||
|             if ($other->email && $other->emailnotifyfav) { | ||||
|                 $this->notify_mail($other, $user, $notice); | ||||
|                 mail_notify_fave($other, $user, $notice); | ||||
|             } | ||||
|             # XXX: notify by IM | ||||
|             # XXX: notify by SMS | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function notify_mail($other, $user, $notice) | ||||
|     { | ||||
|         $profile = $user->getProfile(); | ||||
|         $bestname = $profile->getBestName(); | ||||
|         $subject = sprintf(_('%s added your notice as a favorite'), $bestname); | ||||
|         $body = sprintf(_("%1\$s just added your notice from %2\$s as one of their favorites.\n\n" . | ||||
|                           "In case you forgot, you can see the text of your notice here:\n\n" . | ||||
|                           "%3\$s\n\n" . | ||||
|                           "You can see the list of %1\$s's favorites here:\n\n" . | ||||
|                           "%4\$s\n\n" . | ||||
|                           "Faithfully yours,\n" . | ||||
|                           "%5\$s\n"), | ||||
|                         $bestname, | ||||
|                         common_exact_date($notice->created), | ||||
|                         common_local_url('shownotice', array('notice' => $notice->id)), | ||||
|                         common_local_url('showfavorites', array('nickname' => $user->nickname)), | ||||
|                         common_config('site', 'name')); | ||||
|  | ||||
|         mail_to_user($other, $subject, $body); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -51,6 +51,32 @@ require_once INSTALLDIR.'/lib/twitterapi.php'; | ||||
|  class TwitapigroupsAction extends TwitterapiAction | ||||
|  { | ||||
|  | ||||
|      function show($args, $apidata) | ||||
|      { | ||||
|          parent::handle($args); | ||||
|  | ||||
|          common_debug("in groups api action"); | ||||
|  | ||||
|          $this->auth_user = $apidata['user']; | ||||
|          $group = $this->get_group($apidata['api_arg'], $apidata); | ||||
|  | ||||
|          if (empty($group)) { | ||||
|              $this->clientError('Not Found', 404, $apidata['content-type']); | ||||
|              return; | ||||
|          } | ||||
|  | ||||
|          switch($apidata['content-type']) { | ||||
|           case 'xml': | ||||
|              $this->show_single_xml_group($group); | ||||
|              break; | ||||
|           case 'json': | ||||
|              $this->show_single_json_group($group); | ||||
|              break; | ||||
|           default: | ||||
|              $this->clientError(_('API method not found!'), $code = 404); | ||||
|          } | ||||
|      } | ||||
|  | ||||
|      function timeline($args, $apidata) | ||||
|      { | ||||
|          parent::handle($args); | ||||
| @@ -88,8 +114,7 @@ require_once INSTALLDIR.'/lib/twitterapi.php'; | ||||
|              $this->show_xml_timeline($notice); | ||||
|              break; | ||||
|           case 'rss': | ||||
|              $this->show_rss_timeline($notice, $title, $link, | ||||
|                  $subtitle, $suplink); | ||||
|              $this->show_rss_timeline($notice, $title, $link, $subtitle); | ||||
|              break; | ||||
|           case 'atom': | ||||
|              if (isset($apidata['api_arg'])) { | ||||
| @@ -101,7 +126,7 @@ require_once INSTALLDIR.'/lib/twitterapi.php'; | ||||
|                   'api/laconica/groups/timeline.atom'; | ||||
|              } | ||||
|              $this->show_atom_timeline($notice, $title, $id, $link, | ||||
|                  $subtitle, $suplink, $selfuri); | ||||
|                  $subtitle, null, $selfuri); | ||||
|              break; | ||||
|           case 'json': | ||||
|              $this->show_json_timeline($notice); | ||||
|   | ||||
| @@ -88,8 +88,7 @@ require_once INSTALLDIR.'/lib/twitterapi.php'; | ||||
|              $this->show_xml_timeline($notice); | ||||
|              break; | ||||
|           case 'rss': | ||||
|              $this->show_rss_timeline($notice, $title, $link, | ||||
|                  $subtitle, $suplink); | ||||
|              $this->show_rss_timeline($notice, $title, $link, $subtitle); | ||||
|              break; | ||||
|           case 'atom': | ||||
|              if (isset($apidata['api_arg'])) { | ||||
| @@ -101,7 +100,7 @@ require_once INSTALLDIR.'/lib/twitterapi.php'; | ||||
|                   'api/laconica/tags/timeline.atom'; | ||||
|              } | ||||
|              $this->show_atom_timeline($notice, $title, $id, $link, | ||||
|                  $subtitle, $suplink, $selfuri); | ||||
|                  $subtitle, null, $selfuri); | ||||
|              break; | ||||
|           case 'json': | ||||
|              $this->show_json_timeline($notice); | ||||
|   | ||||
| @@ -55,26 +55,38 @@ class Design extends Memcached_DataObject | ||||
|  | ||||
|     function showCSS($out) | ||||
|     { | ||||
|         try { | ||||
|         $css = ''; | ||||
|  | ||||
|             $bgcolor = new WebColor($this->backgroundcolor); | ||||
|             $ccolor  = new WebColor($this->contentcolor); | ||||
|             $sbcolor = new WebColor($this->sidebarcolor); | ||||
|             $tcolor  = new WebColor($this->textcolor); | ||||
|             $lcolor  = new WebColor($this->linkcolor); | ||||
|         $bgcolor = Design::toWebColor($this->backgroundcolor); | ||||
|  | ||||
|         } catch (WebColorException $e) { | ||||
|             // This shouldn't happen | ||||
|             common_log(LOG_ERR, "Unable to create color for design $id.", | ||||
|                 __FILE__); | ||||
|         if (!empty($bgcolor)) { | ||||
|             $css .= 'body { background-color: #' . $bgcolor->hexValue() . ' }' . "\n"; | ||||
|         } | ||||
|  | ||||
|         $css  = 'body { background-color: #' . $bgcolor->hexValue() . ' }' . "\n"; | ||||
|         $ccolor  = Design::toWebColor($this->contentcolor); | ||||
|  | ||||
|         if (!empty($ccolor)) { | ||||
|             $css .= '#content, #site_nav_local_views .current a { background-color: #'; | ||||
|             $css .= $ccolor->hexValue() . '} '."\n"; | ||||
|         } | ||||
|  | ||||
|         $sbcolor = Design::toWebColor($this->sidebarcolor); | ||||
|  | ||||
|         if (!empty($sbcolor)) { | ||||
|             $css .= '#aside_primary { background-color: #'. $sbcolor->hexValue() . ' }' . "\n"; | ||||
|         } | ||||
|  | ||||
|         $tcolor  = Design::toWebColor($this->textcolor); | ||||
|  | ||||
|         if (!empty($tcolor)) { | ||||
|             $css .= 'html body { color: #'. $tcolor->hexValue() . ' }'. "\n"; | ||||
|         } | ||||
|  | ||||
|         $lcolor  = Design::toWebColor($this->linkcolor); | ||||
|  | ||||
|         if (!empty($lcolor)) { | ||||
|             $css .= 'a { color: #' . $lcolor->hexValue() . ' }' . "\n"; | ||||
|         } | ||||
|  | ||||
|         if (!empty($this->backgroundimage) && | ||||
|             $this->disposition & BACKGROUND_ON) { | ||||
| @@ -88,8 +100,25 @@ class Design extends Memcached_DataObject | ||||
|                 '); ' . $repeat . ' background-attachment:fixed; }' . "\n"; | ||||
|         } | ||||
|  | ||||
|         if (0 != mb_strlen($css)) { | ||||
|             $out->element('style', array('type' => 'text/css'), $css); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     static function toWebColor($color) | ||||
|     { | ||||
|         if (is_null($color)) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         try { | ||||
|             return new WebColor($color); | ||||
|         } catch (WebColorException $e) { | ||||
|             // This shouldn't happen | ||||
|             common_log(LOG_ERR, "Unable to create color for design $id.", | ||||
|                 __FILE__); | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     static function filename($id, $extension, $extra=null) | ||||
| @@ -152,4 +181,33 @@ class Design extends Memcached_DataObject | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Return a design object based on the configured site design. | ||||
|      * | ||||
|      * @return Design a singleton design object for the site. | ||||
|      */ | ||||
|  | ||||
|     static function siteDesign() | ||||
|     { | ||||
|         static $siteDesign = null; | ||||
|  | ||||
|         if (empty($siteDesign)) { | ||||
|  | ||||
|             $siteDesign = new Design(); | ||||
|  | ||||
|             $attrs = array('backgroundcolor', | ||||
|                            'contentcolor', | ||||
|                            'sidebarcolor', | ||||
|                            'textcolor', | ||||
|                            'linkcolor', | ||||
|                            'backgroundimage', | ||||
|                            'disposition'); | ||||
|  | ||||
|             foreach ($attrs as $attr) { | ||||
|                 $siteDesign->$attr = common_config('design', $attr); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $siteDesign; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -93,7 +93,6 @@ class File extends Memcached_DataObject | ||||
|         if (empty($file)) { | ||||
|             $file_redir = File_redirection::staticGet('url', $given_url); | ||||
|             if (empty($file_redir)) { | ||||
|                 common_debug("processNew() '$given_url' not a known redirect.\n"); | ||||
|                 $redir_data = File_redirection::where($given_url); | ||||
|                 $redir_url = $redir_data['url']; | ||||
|                 if ($redir_url === $given_url) { | ||||
| @@ -114,7 +113,9 @@ class File extends Memcached_DataObject | ||||
|  | ||||
|         if (empty($x)) { | ||||
|             $x = File::staticGet($file_id); | ||||
|             if (empty($x)) die('Impossible!'); | ||||
|             if (empty($x)) { | ||||
|                 throw new ServerException("Robin thinks something is impossible."); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         File_to_post::processNew($file_id, $notice_id); | ||||
|   | ||||
| @@ -124,7 +124,6 @@ class Notice extends Memcached_DataObject | ||||
|             $hashtags[] = common_canonical_tag($match[1][$i]); | ||||
|         } | ||||
|  | ||||
|   | ||||
|         /* Add them to the database */ | ||||
|         foreach(array_unique($hashtags) as $hashtag) { | ||||
|             /* elide characters we don't want in the tag */ | ||||
| @@ -197,29 +196,30 @@ class Notice extends Memcached_DataObject | ||||
|             $notice->is_local = $is_local; | ||||
|         } | ||||
|  | ||||
| 		$notice->query('BEGIN'); | ||||
|  | ||||
| 		$notice->reply_to = $reply_to; | ||||
|         if (!empty($created)) { | ||||
|             $notice->created = $created; | ||||
|         } else { | ||||
|             $notice->created = common_sql_now(); | ||||
|         } | ||||
|  | ||||
| 		$notice->content = $final; | ||||
| 		$notice->rendered = common_render_content($final, $notice); | ||||
| 		$notice->source = $source; | ||||
| 		$notice->uri = $uri; | ||||
|  | ||||
|         if (!empty($reply_to)) { | ||||
|             $reply_notice = Notice::staticGet('id', $reply_to); | ||||
|             if (!empty($reply_notice)) { | ||||
|                 $notice->reply_to = $reply_to; | ||||
|                 $notice->conversation = $reply_notice->conversation; | ||||
|             } | ||||
| 		$notice->reply_to = self::getReplyTo($reply_to, $profile_id, $source, $final); | ||||
|  | ||||
|         if (!empty($notice->reply_to)) { | ||||
|             $reply = Notice::staticGet('id', $notice->reply_to); | ||||
|             $notice->conversation = $reply->conversation; | ||||
|         } | ||||
|  | ||||
|         if (Event::handle('StartNoticeSave', array(&$notice))) { | ||||
|  | ||||
|             // XXX: some of these functions write to the DB | ||||
|  | ||||
|             $notice->query('BEGIN'); | ||||
|  | ||||
|             $id = $notice->insert(); | ||||
|  | ||||
|             if (!$id) { | ||||
| @@ -227,18 +227,33 @@ class Notice extends Memcached_DataObject | ||||
|                 return _('Problem saving notice.'); | ||||
|             } | ||||
|  | ||||
|             # Update the URI after the notice is in the database | ||||
|             if (!$uri) { | ||||
|                 $orig = clone($notice); | ||||
|                 $notice->uri = common_notice_uri($notice); | ||||
|             // Update ID-dependent columns: URI, conversation | ||||
|  | ||||
|             $orig = clone($notice); | ||||
|  | ||||
|             $changed = false; | ||||
|  | ||||
|             if (empty($uri)) { | ||||
|                 $notice->uri = common_notice_uri($notice); | ||||
|                 $changed = true; | ||||
|             } | ||||
|  | ||||
|             // If it's not part of a conversation, it's | ||||
|             // the beginning of a new conversation. | ||||
|  | ||||
|             if (empty($notice->conversation)) { | ||||
|                 $notice->conversation = $notice->id; | ||||
|                 $changed = true; | ||||
|             } | ||||
|  | ||||
|             if ($changed) { | ||||
|                 if (!$notice->update($orig)) { | ||||
|                     common_log_db_error($notice, 'UPDATE', __FILE__); | ||||
|                     return _('Problem saving notice.'); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             # XXX: do we need to change this for remote users? | ||||
|             // XXX: do we need to change this for remote users? | ||||
|  | ||||
|             $notice->saveReplies(); | ||||
|             $notice->saveTags(); | ||||
| @@ -246,7 +261,12 @@ class Notice extends Memcached_DataObject | ||||
|             $notice->addToInboxes(); | ||||
|  | ||||
|             $notice->saveUrls(); | ||||
|  | ||||
|             // FIXME: why do we have to re-render the content? | ||||
|             // Remove this if it's not necessary. | ||||
|  | ||||
|             $orig2 = clone($notice); | ||||
|  | ||||
|             $notice->rendered = common_render_content($final, $notice); | ||||
|             if (!$notice->update($orig2)) { | ||||
|                 common_log_db_error($notice, 'UPDATE', __FILE__); | ||||
| @@ -1045,16 +1065,6 @@ class Notice extends Memcached_DataObject | ||||
|             if (!$recipient) { | ||||
|                 continue; | ||||
|             } | ||||
|             if ($i == 0 && ($recipient->id != $sender->id) && !$this->reply_to) { // Don't save reply to self | ||||
|                 $reply_for = $recipient; | ||||
|                 $recipient_notice = $reply_for->getCurrentNotice(); | ||||
|                 if ($recipient_notice) { | ||||
|                     $orig = clone($this); | ||||
|                     $this->reply_to = $recipient_notice->id; | ||||
|                     $this->conversation = $recipient_notice->conversation; | ||||
|                     $this->update($orig); | ||||
|                 } | ||||
|             } | ||||
|             // Don't save replies from blocked profile to local user | ||||
|             $recipient_user = User::staticGet('id', $recipient->id); | ||||
|             if ($recipient_user && $recipient_user->hasBlocked($sender)) { | ||||
| @@ -1101,14 +1111,6 @@ class Notice extends Memcached_DataObject | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // If it's not a reply, make it the root of a new conversation | ||||
|  | ||||
|         if (empty($this->conversation)) { | ||||
|             $orig = clone($this); | ||||
|             $this->conversation = $this->id; | ||||
|             $this->update($orig); | ||||
|         } | ||||
|  | ||||
|         foreach (array_keys($replied) as $recipient) { | ||||
|             $user = User::staticGet('id', $recipient); | ||||
|             if ($user) { | ||||
| @@ -1280,4 +1282,76 @@ class Notice extends Memcached_DataObject | ||||
|  | ||||
|         return $ids; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Determine which notice, if any, a new notice is in reply to. | ||||
|      * | ||||
|      * For conversation tracking, we try to see where this notice fits | ||||
|      * in the tree. Rough algorithm is: | ||||
|      * | ||||
|      * if (reply_to is set and valid) { | ||||
|      *     return reply_to; | ||||
|      * } else if ((source not API or Web) and (content starts with "T NAME" or "@name ")) { | ||||
|      *     return ID of last notice by initial @name in content; | ||||
|      * } | ||||
|      * | ||||
|      * Note that all @nickname instances will still be used to save "reply" records, | ||||
|      * so the notice shows up in the mentioned users' "replies" tab. | ||||
|      * | ||||
|      * @param integer $reply_to   ID passed in by Web or API | ||||
|      * @param integer $profile_id ID of author | ||||
|      * @param string  $source     Source tag, like 'web' or 'gwibber' | ||||
|      * @param string  $content    Final notice content | ||||
|      * | ||||
|      * @return integer ID of replied-to notice, or null for not a reply. | ||||
|      */ | ||||
|  | ||||
|     static function getReplyTo($reply_to, $profile_id, $source, $content) | ||||
|     { | ||||
|         static $lb = array('xmpp', 'mail', 'sms', 'omb'); | ||||
|  | ||||
|         // If $reply_to is specified, we check that it exists, and then | ||||
|         // return it if it does | ||||
|  | ||||
|         if (!empty($reply_to)) { | ||||
|             $reply_notice = Notice::staticGet('id', $reply_to); | ||||
|             if (!empty($reply_notice)) { | ||||
|                 return $reply_to; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // If it's not a "low bandwidth" source (one where you can't set | ||||
|         // a reply_to argument), we return. This is mostly web and API | ||||
|         // clients. | ||||
|  | ||||
|         if (!in_array($source, $lb)) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         // Is there an initial @ or T? | ||||
|  | ||||
|         if (preg_match('/^T ([A-Z0-9]{1,64}) /', $content, $match) || | ||||
|             preg_match('/^@([a-z0-9]{1,64})\s+/', $content, $match)) { | ||||
|             $nickname = common_canonical_nickname($match[1]); | ||||
|         } else { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         // Figure out who that is. | ||||
|  | ||||
|         $sender = Profile::staticGet('id', $profile_id); | ||||
|         $recipient = common_relative_profile($sender, $nickname, common_sql_now()); | ||||
|  | ||||
|         if (empty($recipient)) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         // Get their last notice | ||||
|  | ||||
|         $last = $recipient->getCurrentNotice(); | ||||
|  | ||||
|         if (!empty($last)) { | ||||
|             return $last->id; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -108,11 +108,24 @@ class Session extends Memcached_DataObject | ||||
|  | ||||
|         $epoch = common_sql_date(time() - $maxlifetime); | ||||
|  | ||||
|         $ids = array(); | ||||
|  | ||||
|         $session = new Session(); | ||||
|         $session->whereAdd('modified < "'.$epoch.'"'); | ||||
|         $result = $session->delete(DB_DATAOBJECT_WHEREADD_ONLY); | ||||
|         $session->selectAdd(); | ||||
|         $session->selectAdd('id'); | ||||
|  | ||||
|         self::logdeb("garbage collection result = $result"); | ||||
|         $session->find(); | ||||
|  | ||||
|         while ($session->fetch()) { | ||||
|             $ids[] = $session->id; | ||||
|         } | ||||
|  | ||||
|         $session->free(); | ||||
|  | ||||
|         foreach ($ids as $id) { | ||||
|             self::destroy($id); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     static function setSaveHandler() | ||||
|   | ||||
| @@ -18,14 +18,14 @@ $config['site']['server'] = 'localhost'; | ||||
| $config['site']['path'] = 'laconica'; | ||||
| // $config['site']['fancy'] = false; | ||||
| // $config['site']['theme'] = 'default'; | ||||
| // Sets the site's default design values (match it with the values in the theme) | ||||
| // $config['site']['design']['backgroundcolor'] = '#F0F2F5'; | ||||
| // $config['site']['design']['contentcolor'] = '#FFFFFF'; | ||||
| // $config['site']['design']['sidebarcolor'] = '#CEE1E9'; | ||||
| // $config['site']['design']['textcolor'] = '#000000'; | ||||
| // $config['site']['design']['linkcolor'] = '#002E6E'; | ||||
| // $config['site']['design']['backgroundimage'] = null; | ||||
| // $config['site']['design']['disposition'] = 1; | ||||
| // Sets the site's default design values | ||||
| // $config['design']['backgroundcolor'] = '#F0F2F5'; | ||||
| // $config['design']['contentcolor'] = '#FFFFFF'; | ||||
| // $config['design']['sidebarcolor'] = '#CEE1E9'; | ||||
| // $config['design']['textcolor'] = '#000000'; | ||||
| // $config['design']['linkcolor'] = '#002E6E'; | ||||
| // $config['design']['backgroundimage'] = null; | ||||
| // $config['design']['disposition'] = 1; | ||||
| // To enable the built-in mobile style sheet, defaults to false. | ||||
| // $config['site']['mobile'] = true; | ||||
| // For contact email, defaults to $_SERVER["SERVER_ADMIN"] | ||||
|   | ||||
							
								
								
									
										108
									
								
								db/074to080_pg.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								db/074to080_pg.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| BEGIN; | ||||
| create sequence design_seq; | ||||
| create table design ( | ||||
|     id bigint default nextval('design_seq') /* comment 'design ID'*/, | ||||
|     backgroundcolor integer /* comment 'main background color'*/ , | ||||
|     contentcolor integer /*comment 'content area background color'*/ , | ||||
|     sidebarcolor integer /*comment 'sidebar background color'*/ , | ||||
|     textcolor integer /*comment 'text color'*/ , | ||||
|     linkcolor integer /*comment 'link color'*/, | ||||
|     backgroundimage varchar(255) /*comment 'background image, if any'*/, | ||||
|     disposition int default 1 /*comment 'bit 1 = hide background image, bit 2 = display background image, bit 4 = tile background image'*/, | ||||
|     primary key (id) | ||||
| ); | ||||
| alter table "user" | ||||
|      add column design_id integer references design(id); | ||||
| alter table "user" | ||||
|      add column viewdesigns integer default 1; | ||||
|  | ||||
| alter table notice add column | ||||
|      conversation integer references notice (id); | ||||
|  | ||||
| create index notice_conversation_idx on notice(conversation); | ||||
|  | ||||
| alter table foreign_user | ||||
|      alter column id TYPE bigint; | ||||
|       | ||||
| alter table foreign_user alter column id set not null; | ||||
|  | ||||
| alter table foreign_link | ||||
|      alter column foreign_id TYPE bigint; | ||||
|  | ||||
| alter table user_group | ||||
|       add column design_id integer; | ||||
|  | ||||
| /*attachments and URLs stuff */ | ||||
| create sequence file_seq; | ||||
| create table file ( | ||||
|     id bigint default nextval('file_seq') primary key /* comment 'unique identifier' */, | ||||
|     url varchar(255) unique,  | ||||
|     mimetype varchar(50),  | ||||
|     size integer,  | ||||
|     title varchar(255),  | ||||
|     date integer,  | ||||
|     protected integer, | ||||
|     filename text /* comment 'if a local file, name of the file' */, | ||||
|     modified timestamp default CURRENT_TIMESTAMP /* comment 'date this record was modified'*/ | ||||
| ); | ||||
|  | ||||
| create sequence file_oembed_seq; | ||||
| create table file_oembed ( | ||||
|     file_id bigint default nextval('file_oembed_seq') primary key /* comment 'unique identifier' */, | ||||
|     version varchar(20), | ||||
|     type varchar(20), | ||||
|     provider varchar(50), | ||||
|     provider_url varchar(255), | ||||
|     width integer, | ||||
|     height integer, | ||||
|     html text, | ||||
|     title varchar(255), | ||||
|     author_name varchar(50),  | ||||
|     author_url varchar(255),  | ||||
|     url varchar(255)  | ||||
| ); | ||||
|  | ||||
| create sequence file_redirection_seq; | ||||
| create table file_redirection ( | ||||
|     url varchar(255) primary key,  | ||||
|     file_id bigint,  | ||||
|     redirections integer,  | ||||
|     httpcode integer | ||||
| ); | ||||
|  | ||||
| create sequence file_thumbnail_seq; | ||||
| create table file_thumbnail ( | ||||
|     file_id bigint primary key,  | ||||
|     url varchar(255) unique,  | ||||
|     width integer,  | ||||
|     height integer  | ||||
| ); | ||||
| create sequence file_to_post_seq; | ||||
| create table file_to_post ( | ||||
|     file_id bigint,  | ||||
|     post_id bigint,  | ||||
|  | ||||
|     primary key (file_id, post_id) | ||||
| ); | ||||
|  | ||||
|  | ||||
| create table group_block ( | ||||
|    group_id integer not null /* comment 'group profile is blocked from' */ references user_group (id), | ||||
|    blocked integer not null /* comment 'profile that is blocked' */references profile (id), | ||||
|    blocker integer not null /* comment 'user making the block'*/ references "user" (id), | ||||
|    modified timestamp /* comment 'date of blocking'*/ , | ||||
|  | ||||
|    primary key (group_id, blocked) | ||||
| ); | ||||
|  | ||||
| create table group_alias ( | ||||
|  | ||||
|    alias varchar(64) /* comment 'additional nickname for the group'*/ , | ||||
|    group_id integer not null /* comment 'group profile is blocked from'*/ references user_group (id), | ||||
|    modified timestamp /* comment 'date alias was created'*/, | ||||
|    primary key (alias) | ||||
|  | ||||
| ); | ||||
| create index group_alias_group_id_idx on group_alias (group_id); | ||||
|  | ||||
| COMMIT; | ||||
| @@ -108,7 +108,7 @@ function checkMirror($action_obj) | ||||
| function main() | ||||
| { | ||||
|     // quick check for fancy URL auto-detection support in installer. | ||||
|     if (isset($_SERVER['REDIRECT_URL']) && ((dirname($_SERVER['REQUEST_URI']) . '/check-fancy') === $_SERVER['REDIRECT_URL'])) { | ||||
|     if (isset($_SERVER['REDIRECT_URL']) && (preg_replace("/^\/$/","",(dirname($_SERVER['REQUEST_URI']))) . '/check-fancy') === $_SERVER['REDIRECT_URL']) { | ||||
|         die("Fancy URL support detection succeeded. We suggest you enable this to get fancy (pretty) URLs."); | ||||
|     } | ||||
|     global $user, $action; | ||||
|   | ||||
							
								
								
									
										10
									
								
								install.php
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								install.php
									
									
									
									
									
								
							| @@ -77,7 +77,7 @@ function checkPrereqs() | ||||
| 		if (!is_writable($fileFullPath)) { | ||||
|     	     ?><p class="error">Cannot write <?php echo $fileSubdir; ?> directory: <code><?php echo $fileFullPath; ?></code></p> | ||||
| 		       <p>On your server, try this command: <code>chmod a+w <?php echo $fileFullPath; ?></code></p> | ||||
|     	     <? | ||||
| 	     <?php | ||||
| 		     $pass = false; | ||||
| 		} | ||||
| 	} | ||||
| @@ -219,9 +219,9 @@ function handlePost() | ||||
|     } | ||||
|      | ||||
|     switch($dbtype) { | ||||
|       case 'mysql':    mysql_db_installer($host, $database, $username, $password, $sitename); | ||||
|       case 'mysql':    mysql_db_installer($host, $database, $username, $password, $sitename, $fancy); | ||||
|       break; | ||||
|       case 'pgsql':    pgsql_db_installer($host, $database, $username, $password, $sitename); | ||||
|       case 'pgsql':    pgsql_db_installer($host, $database, $username, $password, $sitename, $fancy); | ||||
|       break; | ||||
|       default: | ||||
|     } | ||||
| @@ -232,7 +232,7 @@ function handlePost() | ||||
| <?php | ||||
| } | ||||
|  | ||||
| function pgsql_db_installer($host, $database, $username, $password, $sitename) { | ||||
| function pgsql_db_installer($host, $database, $username, $password, $sitename, $fancy) { | ||||
|   $connstring = "dbname=$database host=$host user=$username"; | ||||
|  | ||||
|   //No password would mean trust authentication used. | ||||
| @@ -298,7 +298,7 @@ function pgsql_db_installer($host, $database, $username, $password, $sitename) { | ||||
|        | ||||
| } | ||||
|  | ||||
| function mysql_db_installer($host, $database, $username, $password, $sitename) { | ||||
| function mysql_db_installer($host, $database, $username, $password, $sitename, $fancy) { | ||||
|   updateStatus("Starting installation..."); | ||||
|   updateStatus("Checking database..."); | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,35 @@ | ||||
|  * @link      http://laconi.ca/ | ||||
|  */ | ||||
| $(document).ready(function() { | ||||
|     function InitColors(i, E) { | ||||
|         switch (parseInt(E.id.slice(-1))) { | ||||
|             case 1: default: | ||||
|                 $(E).val(rgb2hex($('body').css('background-color'))); | ||||
|                 break; | ||||
|             case 2: | ||||
|                 $(E).val(rgb2hex($('#content').css('background-color'))); | ||||
|                 break; | ||||
|             case 3: | ||||
|                 $(E).val(rgb2hex($('#aside_primary').css('background-color'))); | ||||
|                 break; | ||||
|             case 4: | ||||
|                 $(E).val(rgb2hex($('html body').css('color'))); | ||||
|                 break; | ||||
|             case 5: | ||||
|                 $(E).val(rgb2hex($('a').css('color'))); | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function rgb2hex(rgb) { | ||||
|         rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); | ||||
|         function hex(x) { | ||||
|             hexDigits = new Array("0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"); | ||||
|             return isNaN(x) ? "00" : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16]; | ||||
|         } | ||||
|         return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]); | ||||
|     } | ||||
|  | ||||
|     function UpdateColors(S) { | ||||
|         C = $(S).val(); | ||||
|         switch (parseInt(S.id.slice(-1))) { | ||||
| @@ -55,7 +84,7 @@ $(document).ready(function() { | ||||
|  | ||||
|         f = $.farbtastic('#color-picker', SynchColors); | ||||
|         swatches = $('#settings_design_color .swatch'); | ||||
|  | ||||
|         swatches.each(InitColors); | ||||
|         swatches | ||||
|             .each(SynchColors) | ||||
|             .blur(function() { | ||||
|   | ||||
| @@ -191,6 +191,7 @@ class Action extends HTMLOutputter // lawsuit | ||||
|     function showStylesheets() | ||||
|     { | ||||
|         if (Event::handle('StartShowStyles', array($this))) { | ||||
|  | ||||
|             if (Event::handle('StartShowLaconicaStyles', array($this))) { | ||||
|                 $this->element('link', array('rel' => 'stylesheet', | ||||
|                                              'type' => 'text/css', | ||||
| @@ -209,6 +210,7 @@ class Action extends HTMLOutputter // lawsuit | ||||
|                                              'media' => 'print')); | ||||
|                 Event::handle('EndShowLaconicaStyles', array($this)); | ||||
|             } | ||||
|  | ||||
|             if (Event::handle('StartShowUAStyles', array($this))) { | ||||
|                 $this->comment('[if IE]><link rel="stylesheet" type="text/css" '. | ||||
|                                'href="'.theme_path('css/ie.css', 'base').'?version='.LACONICA_VERSION.'" /><![endif]'); | ||||
| @@ -223,6 +225,21 @@ class Action extends HTMLOutputter // lawsuit | ||||
|                                'href="'.theme_path('css/ie.css', null).'?version='.LACONICA_VERSION.'" /><![endif]'); | ||||
|                 Event::handle('EndShowUAStyles', array($this)); | ||||
|             } | ||||
|  | ||||
|             if (Event::handle('StartShowDesign', array($this))) { | ||||
|  | ||||
|                 $user = common_current_user(); | ||||
|  | ||||
|                 if (empty($user) || $user->viewdesigns) { | ||||
|                     $design = $this->getDesign(); | ||||
|  | ||||
|                     if (!empty($design)) { | ||||
|                         $design->showCSS($this); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 Event::handle('EndShowDesign', array($this)); | ||||
|             } | ||||
|             Event::handle('EndShowStyles', array($this)); | ||||
|         } | ||||
|     } | ||||
| @@ -1074,4 +1091,15 @@ class Action extends HTMLOutputter // lawsuit | ||||
|     { | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * A design for this action | ||||
|      * | ||||
|      * @return Design a design object to use | ||||
|      */ | ||||
|  | ||||
|     function getDesign() | ||||
|     { | ||||
|         return Design::siteDesign(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -94,14 +94,6 @@ $config = | ||||
|         array('name' => 'Just another Laconica microblog', | ||||
|               'server' => $_server, | ||||
|               'theme' => 'default', | ||||
|               'design' => | ||||
|               array('backgroundcolor' => '#CEE1E9', | ||||
|                     'contentcolor' => '#FFFFFF', | ||||
|                     'sidebarcolor' => '#C8D1D5', | ||||
|                     'textcolor' => '#000000', | ||||
|                     'linkcolor' => '#002E6E', | ||||
|                     'backgroundimage' => null, | ||||
|                     'disposition' => 1), | ||||
|               'path' => $_path, | ||||
|               'logfile' => null, | ||||
|               'logo' => null, | ||||
| @@ -261,6 +253,14 @@ $config = | ||||
|         'sessions' => | ||||
|         array('handle' => false, // whether to handle sessions ourselves | ||||
|               'debug' => false), // debugging output for sessions | ||||
|         'design' => | ||||
|         array('backgroundcolor' => null, // null -> 'use theme default' | ||||
|               'contentcolor' => null, | ||||
|               'sidebarcolor' => null, | ||||
|               'textcolor' => null, | ||||
|               'linkcolor' => null, | ||||
|               'backgroundimage' => null, | ||||
|               'disposition' => null), | ||||
|         ); | ||||
|  | ||||
| $config['db'] = &PEAR::getStaticProperty('DB_DataObject','options'); | ||||
| @@ -277,6 +277,10 @@ $config['db'] = | ||||
|         'quote_identifiers' => false, | ||||
|         'type' => 'mysql' ); | ||||
|  | ||||
| // Backward compatibility | ||||
|  | ||||
| $config['site']['design'] =& $config['design']; | ||||
|  | ||||
| if (function_exists('date_default_timezone_set')) { | ||||
|     /* Work internally in UTC */ | ||||
|     date_default_timezone_set('UTC'); | ||||
|   | ||||
| @@ -47,33 +47,10 @@ if (!defined('LACONICA')) { | ||||
|  | ||||
| class CurrentUserDesignAction extends Action | ||||
| { | ||||
|  | ||||
|     /** | ||||
|       * Show the user's design stylesheet | ||||
|       * | ||||
|       * @return nothing | ||||
|       */ | ||||
|  | ||||
|      function showStylesheets() | ||||
|      { | ||||
|          parent::showStylesheets(); | ||||
|  | ||||
|          $user = common_current_user(); | ||||
|  | ||||
|          if (empty($user) || $user->viewdesigns) { | ||||
|              $design = $this->getDesign(); | ||||
|  | ||||
|              if (!empty($design)) { | ||||
|                  $design->showCSS($this); | ||||
|              } | ||||
|          } | ||||
|      } | ||||
|  | ||||
|     /** | ||||
|      * A design for this action | ||||
|      * | ||||
|      * if the user attribute has been set, returns that user's | ||||
|      * design. | ||||
|      * Returns the design preferences for the current user. | ||||
|      * | ||||
|      * @return Design a design object to use | ||||
|      */ | ||||
| @@ -82,11 +59,15 @@ class CurrentUserDesignAction extends Action | ||||
|     { | ||||
|         $cur = common_current_user(); | ||||
|  | ||||
|         if (empty($cur)) { | ||||
|             return null; | ||||
|         if (!empty($cur)) { | ||||
|  | ||||
|             $design = $cur->getDesign(); | ||||
|  | ||||
|             if (!empty($design)) { | ||||
|                 return $design; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $cur->getDesign(); | ||||
|         return parent::getDesign(); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -182,7 +182,7 @@ class DesignSettingsAction extends AccountSettingsAction | ||||
|                                           'class' => 'swatch', | ||||
|                                           'maxlength' => '7', | ||||
|                                           'size' => '7', | ||||
|                                           'value' => '#' . $bgcolor->hexValue())); | ||||
|                                           'value' => '')); | ||||
|             $this->elementEnd('li'); | ||||
|  | ||||
|             $ccolor = new WebColor($design->contentcolor); | ||||
| @@ -195,7 +195,7 @@ class DesignSettingsAction extends AccountSettingsAction | ||||
|                                           'class' => 'swatch', | ||||
|                                           'maxlength' => '7', | ||||
|                                           'size' => '7', | ||||
|                                           'value' => '#' . $ccolor->hexValue())); | ||||
|                                           'value' => '')); | ||||
|             $this->elementEnd('li'); | ||||
|  | ||||
|             $sbcolor = new WebColor($design->sidebarcolor); | ||||
| @@ -208,7 +208,7 @@ class DesignSettingsAction extends AccountSettingsAction | ||||
|                                         'class' => 'swatch', | ||||
|                                         'maxlength' => '7', | ||||
|                                         'size' => '7', | ||||
|                                         'value' => '#' . $sbcolor->hexValue())); | ||||
|                                         'value' => '')); | ||||
|             $this->elementEnd('li'); | ||||
|  | ||||
|             $tcolor = new WebColor($design->textcolor); | ||||
| @@ -221,7 +221,7 @@ class DesignSettingsAction extends AccountSettingsAction | ||||
|                                         'class' => 'swatch', | ||||
|                                         'maxlength' => '7', | ||||
|                                         'size' => '7', | ||||
|                                         'value' => '#' . $tcolor->hexValue())); | ||||
|                                         'value' => '')); | ||||
|             $this->elementEnd('li'); | ||||
|  | ||||
|             $lcolor = new WebColor($design->linkcolor); | ||||
| @@ -234,7 +234,7 @@ class DesignSettingsAction extends AccountSettingsAction | ||||
|                                          'class' => 'swatch', | ||||
|                                          'maxlength' => '7', | ||||
|                                          'size' => '7', | ||||
|                                          'value' => '#' . $lcolor->hexValue())); | ||||
|                                          'value' => '')); | ||||
|             $this->elementEnd('li'); | ||||
|  | ||||
|         } catch (WebColorException $e) { | ||||
|   | ||||
| @@ -49,26 +49,6 @@ class GroupDesignAction extends Action { | ||||
|     /** The group in question */ | ||||
|     var $group = null; | ||||
|  | ||||
|     /** | ||||
|       * Show the groups's design stylesheet | ||||
|       * | ||||
|       * @return nothing | ||||
|       */ | ||||
|      function showStylesheets() | ||||
|      { | ||||
|          parent::showStylesheets(); | ||||
|  | ||||
|          $user = common_current_user(); | ||||
|  | ||||
|          if (empty($user) || $user->viewdesigns) { | ||||
|              $design = $this->getDesign(); | ||||
|  | ||||
|              if (!empty($design)) { | ||||
|                  $design->showCSS($this); | ||||
|              } | ||||
|          } | ||||
|      } | ||||
|  | ||||
|     /** | ||||
|      * A design for this action | ||||
|      * | ||||
| @@ -80,10 +60,12 @@ class GroupDesignAction extends Action { | ||||
|  | ||||
|     function getDesign() | ||||
|     { | ||||
|         if (empty($this->group)) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         return $this->group->getDesign(); | ||||
|         if (!empty($this->group)) { | ||||
|             $design = $this->group->getDesign(); | ||||
|             if (!empty($design)) { | ||||
|                 return $design; | ||||
|             } | ||||
|         } | ||||
|         return parent::getDesign(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -52,26 +52,6 @@ class OwnerDesignAction extends Action { | ||||
|  | ||||
|     var $user = null; | ||||
|  | ||||
|     /** | ||||
|       * Show the owner's design stylesheet | ||||
|       * | ||||
|       * @return nothing | ||||
|       */ | ||||
|      function showStylesheets() | ||||
|      { | ||||
|          parent::showStylesheets(); | ||||
|  | ||||
|          $user = common_current_user(); | ||||
|  | ||||
|          if (empty($user) || $user->viewdesigns) { | ||||
|              $design = $this->getDesign(); | ||||
|  | ||||
|              if (!empty($design)) { | ||||
|                  $design->showCSS($this); | ||||
|              } | ||||
|          } | ||||
|      } | ||||
|  | ||||
|     /** | ||||
|      * A design for this action | ||||
|      * | ||||
| @@ -83,10 +63,15 @@ class OwnerDesignAction extends Action { | ||||
|  | ||||
|     function getDesign() | ||||
|     { | ||||
|         if (empty($this->user)) { | ||||
|             return null; | ||||
|         if (!empty($this->user)) { | ||||
|  | ||||
|             $design = $this->user->getDesign(); | ||||
|  | ||||
|             if (!empty($design)) { | ||||
|                 return $design; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $this->user->getDesign(); | ||||
|         return parent::getDesign(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -113,6 +113,16 @@ class Router | ||||
|  | ||||
|         $m->connect('main/tagother/:id', array('action' => 'tagother')); | ||||
|  | ||||
|         $m->connect('main/oembed.xml', | ||||
|                     array('action' => 'api', | ||||
|                           'method' => 'oembed.xml', | ||||
|                           'apiaction' => 'oembed')); | ||||
|  | ||||
|         $m->connect('main/oembed.json', | ||||
|                     array('action' => 'api', | ||||
|                           'method' => 'oembed.json', | ||||
|                           'apiaction' => 'oembed')); | ||||
|  | ||||
|         // these take a code | ||||
|  | ||||
|         foreach (array('register', 'confirmaddress', 'recoverpassword') as $c) { | ||||
| @@ -129,11 +139,6 @@ class Router | ||||
|             $m->connect('index.php?action=' . $action, array('action' => $action)); | ||||
|         } | ||||
|  | ||||
|         $m->connect('main/:method', | ||||
|                     array('action' => 'api', | ||||
|                           'method' => 'oembed(.xml|.json)?', | ||||
|                           'apiaction' => 'oembed')); | ||||
|  | ||||
|         // settings | ||||
|  | ||||
|         foreach (array('profile', 'avatar', 'password', 'openid', 'im', | ||||
|   | ||||
| @@ -213,6 +213,26 @@ class TwitterapiAction extends Action | ||||
|         return $twitter_status; | ||||
|     } | ||||
|  | ||||
|     function twitter_group_array($group) | ||||
|     { | ||||
|         $twitter_group=array(); | ||||
|         $twitter_group['id']=$group->id; | ||||
|         $twitter_group['url']=$group->permalink(); | ||||
|         $twitter_group['nickname']=$group->nickname; | ||||
|         $twitter_group['fullname']=$group->fullname; | ||||
|         $twitter_group['homepage_url']=$group->homepage_url; | ||||
|         $twitter_group['original_logo']=$group->original_logo; | ||||
|         $twitter_group['homepage_logo']=$group->homepage_logo; | ||||
|         $twitter_group['stream_logo']=$group->stream_logo; | ||||
|         $twitter_group['mini_logo']=$group->mini_logo; | ||||
|         $twitter_group['homepage']=$group->homepage; | ||||
|         $twitter_group['description']=$group->description; | ||||
|         $twitter_group['location']=$group->location; | ||||
|         $twitter_group['created']=$this->date_twitter($group->created); | ||||
|         $twitter_group['modified']=$this->date_twitter($group->modified); | ||||
|         return $twitter_group; | ||||
|     } | ||||
|  | ||||
|     function twitter_rss_entry_array($notice) | ||||
|     { | ||||
|         $profile = $notice->getProfile(); | ||||
| @@ -413,6 +433,15 @@ class TwitterapiAction extends Action | ||||
|         $this->elementEnd('status'); | ||||
|     } | ||||
|  | ||||
|     function show_twitter_xml_group($twitter_group) | ||||
|     { | ||||
|         $this->elementStart('group'); | ||||
|         foreach($twitter_group as $element => $value) { | ||||
|             $this->element($element, null, $value); | ||||
|         } | ||||
|         $this->elementEnd('group'); | ||||
|     } | ||||
|  | ||||
|     function show_twitter_xml_user($twitter_user, $role='user') | ||||
|     { | ||||
|         $this->elementStart($role); | ||||
| @@ -450,12 +479,12 @@ class TwitterapiAction extends Action | ||||
|         $this->element('link', null, $entry['link']); | ||||
|  | ||||
|         # RSS only supports 1 enclosure per item | ||||
|         if($entry['enclosures']){ | ||||
|         if(array_key_exists('enclosures', $entry) and !empty($entry['enclosures'])){ | ||||
|             $enclosure = $entry['enclosures'][0]; | ||||
|             $this->element('enclosure', array('url'=>$enclosure['url'],'type'=>$enclosure['mimetype'],'length'=>$enclosure['size']), null); | ||||
|         } | ||||
|          | ||||
|         if($entry['tags']){ | ||||
|         if(array_key_exists('tags', $entry)){ | ||||
|             foreach($entry['tags'] as $tag){ | ||||
|                 $this->element('category', null,$tag); | ||||
|             } | ||||
| @@ -639,6 +668,22 @@ class TwitterapiAction extends Action | ||||
|         $this->end_document('json'); | ||||
|     } | ||||
|  | ||||
|     function show_single_json_group($group) | ||||
|     { | ||||
|         $this->init_document('json'); | ||||
|         $twitter_group = $this->twitter_group_array($group); | ||||
|         $this->show_json_objects($twitter_group); | ||||
|         $this->end_document('json'); | ||||
|     } | ||||
|  | ||||
|     function show_single_xml_group($group) | ||||
|     { | ||||
|         $this->init_document('xml'); | ||||
|         $twitter_group = $this->twitter_group_array($group); | ||||
|         $this->show_twitter_xml_group($twitter_group); | ||||
|         $this->end_document('xml'); | ||||
|     } | ||||
|  | ||||
|     // Anyone know what date format this is? | ||||
|     // Twitter's dates look like this: "Mon Jul 14 23:52:38 +0000 2008" -- Zach | ||||
|     function date_twitter($dt) | ||||
|   | ||||
							
								
								
									
										11
									
								
								lib/util.php
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								lib/util.php
									
									
									
									
									
								
							| @@ -140,7 +140,7 @@ function common_have_session() | ||||
| function common_ensure_session() | ||||
| { | ||||
|     $c = null; | ||||
|     if (array_key_exists(session_name, $_COOKIE)) { | ||||
|     if (array_key_exists(session_name(), $_COOKIE)) { | ||||
|         $c = $_COOKIE[session_name()]; | ||||
|     } | ||||
|     if (!common_have_session()) { | ||||
| @@ -1410,20 +1410,21 @@ function common_client_ip() | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     if ($_SERVER['HTTP_X_FORWARDED_FOR']) { | ||||
|         if ($_SERVER['HTTP_CLIENT_IP']) { | ||||
|     if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) { | ||||
|         if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) { | ||||
|             $proxy = $_SERVER['HTTP_CLIENT_IP']; | ||||
|         } else { | ||||
|             $proxy = $_SERVER['REMOTE_ADDR']; | ||||
|         } | ||||
|         $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; | ||||
|     } else { | ||||
|         if ($_SERVER['HTTP_CLIENT_IP']) { | ||||
|         $proxy = null; | ||||
|         if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) { | ||||
|             $ip = $_SERVER['HTTP_CLIENT_IP']; | ||||
|         } else { | ||||
|             $ip = $_SERVER['REMOTE_ADDR']; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return array($ip, $proxy); | ||||
|     return array($proxy, $ip); | ||||
| } | ||||
|   | ||||
| @@ -122,9 +122,7 @@ class FBConnectPlugin extends Plugin | ||||
|                                     FB_RequireFeatures( | ||||
|                                         ["XFBML"], | ||||
|                                             function() { | ||||
|                                                 FB.init("%s", "../xd_receiver.html", | ||||
|                                                  {"doNotUseCachedConnectState":true }); | ||||
|  | ||||
|                                                 FB.init("%s", "../xd_receiver.html"); | ||||
|                                             } | ||||
|                                         ); } | ||||
|  | ||||
| @@ -222,7 +220,7 @@ class FBConnectPlugin extends Plugin | ||||
|                 try { | ||||
|  | ||||
|                     $facebook = getFacebook(); | ||||
|                     $fbuid    = $facebook->api_client->users_getLoggedInUser(); | ||||
|                     $fbuid    = $facebook->get_loggedin_user(); | ||||
|  | ||||
|                 } catch (Exception $e) { | ||||
|                     common_log(LOG_WARNING, | ||||
|   | ||||
							
								
								
									
										22
									
								
								plugins/recaptcha/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								plugins/recaptcha/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net | ||||
| AUTHORS: | ||||
|   Mike Crawford | ||||
|   Ben Maurer | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
|  | ||||
| The above copyright notice and this permission notice shall be included in | ||||
| all copies or substantial portions of the Software. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
| THE SOFTWARE. | ||||
							
								
								
									
										23
									
								
								plugins/recaptcha/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								plugins/recaptcha/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| Laconica reCAPTCHA plugin 0.2 8/3/09 | ||||
| ==================================== | ||||
| Adds a captcha to your registration page to reduce automated spam bots registering. | ||||
|  | ||||
| Use: | ||||
| 1. Get an API key from http://recaptcha.net | ||||
|  | ||||
| 2. In config.php add: | ||||
| include_once('plugins/recaptcha.php'); | ||||
| $captcha = new recaptcha(publickey, privatekey, showErrors); | ||||
|  | ||||
| Changelog | ||||
| ========= | ||||
| 0.1 initial release | ||||
| 0.2 Work around for webkit browsers | ||||
|  | ||||
| reCAPTCHA README | ||||
| ================ | ||||
|  | ||||
| The reCAPTCHA PHP Lirary helps you use the reCAPTCHA API. Documentation | ||||
| for this library can be found at | ||||
|  | ||||
| 	http://recaptcha.net/plugins/php | ||||
							
								
								
									
										106
									
								
								plugins/recaptcha/recaptcha.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								plugins/recaptcha/recaptcha.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Laconica, the distributed open-source microblogging tool | ||||
|  * | ||||
|  * Plugin to show reCaptcha when a user registers  | ||||
|  * | ||||
|  * PHP version 5 | ||||
|  * | ||||
|  * LICENCE: This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Affero General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU Affero General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  * | ||||
|  * @category  Plugin | ||||
|  * @package   Laconica | ||||
|  * @author    Eric Helgeson <erichelgeson@gmail.com> | ||||
|  * @copyright 2009 | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 | ||||
|  * @link      http://laconi.ca/ | ||||
|  */ | ||||
|  | ||||
| if (!defined('LACONICA')) { | ||||
|     exit(1); | ||||
| } | ||||
|  | ||||
| define('RECAPTCHA', '0.2'); | ||||
|  | ||||
| class recaptcha extends Plugin | ||||
| { | ||||
|     var $private_key; | ||||
|     var $public_key; | ||||
|     var $display_errors; | ||||
|     var $failed; | ||||
|     var $ssl; | ||||
|  | ||||
|     function __construct($public_key, $private_key, $display_errors=false) | ||||
|     { | ||||
|         parent::__construct(); | ||||
|         require_once(INSTALLDIR.'/plugins/recaptcha/recaptchalib.php'); | ||||
|         $this->public_key = $public_key; | ||||
|         $this->private_key = $private_key;  | ||||
|         $this->display_errors = $display_errors; | ||||
|     } | ||||
|  | ||||
|     function checkssl(){ | ||||
|         if(common_config('site', 'ssl') === 'sometimes' || common_config('site', 'ssl') === 'always') { | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     function onStartShowHTML($action) | ||||
|     { | ||||
|         //XXX: Horrible hack to make Safari, FF2, and Chrome work with | ||||
|         //reChapcha. reChapcha beaks xhtml strict | ||||
|         header('Content-Type: text/html'); | ||||
|  | ||||
|         $action->extraHeaders(); | ||||
|  | ||||
|         $action->startXML('html', | ||||
|             '-//W3C//DTD XHTML 1.0 Strict//EN', | ||||
|             'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'); | ||||
|  | ||||
|         $action->raw('<style type="text/css">#recaptcha_area{float:left;}</style>'); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     function onEndRegistrationFormData($action) | ||||
|     { | ||||
|         $action->elementStart('li'); | ||||
|         $action->raw('<label for="recaptcha_area">Captcha</label>'); | ||||
|         if($this->checkssl() === true){ | ||||
|             $action->raw(recaptcha_get_html($this->public_key), null, true); | ||||
|         } else {  | ||||
|             $action->raw(recaptcha_get_html($this->public_key)); | ||||
|         } | ||||
|         $action->elementEnd('li'); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     function onStartRegistrationTry($action) | ||||
|     { | ||||
|         $resp = recaptcha_check_answer ($this->private_key, | ||||
|                                         $_SERVER["REMOTE_ADDR"], | ||||
|                                         $action->trimmed('recaptcha_challenge_field'), | ||||
|                                         $action->trimmed('recaptcha_response_field')); | ||||
|  | ||||
|         if (!$resp->is_valid)  | ||||
|         { | ||||
|             if($this->display_errors) | ||||
|             {  | ||||
|                 $action->showForm ("(reCAPTCHA said: " . $resp->error . ")"); | ||||
|             } | ||||
|             $action->showForm("Captcha does not match!"); | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										277
									
								
								plugins/recaptcha/recaptchalib.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										277
									
								
								plugins/recaptcha/recaptchalib.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,277 @@ | ||||
| <?php | ||||
| /* | ||||
|  * This is a PHP library that handles calling reCAPTCHA. | ||||
|  *    - Documentation and latest version | ||||
|  *          http://recaptcha.net/plugins/php/ | ||||
|  *    - Get a reCAPTCHA API Key | ||||
|  *          http://recaptcha.net/api/getkey | ||||
|  *    - Discussion group | ||||
|  *          http://groups.google.com/group/recaptcha | ||||
|  * | ||||
|  * Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net | ||||
|  * AUTHORS: | ||||
|  *   Mike Crawford | ||||
|  *   Ben Maurer | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * The reCAPTCHA server URL's | ||||
|  */ | ||||
| define("RECAPTCHA_API_SERVER", "http://api.recaptcha.net"); | ||||
| define("RECAPTCHA_API_SECURE_SERVER", "https://api-secure.recaptcha.net"); | ||||
| define("RECAPTCHA_VERIFY_SERVER", "api-verify.recaptcha.net"); | ||||
|  | ||||
| /** | ||||
|  * Encodes the given data into a query string format | ||||
|  * @param $data - array of string elements to be encoded | ||||
|  * @return string - encoded request | ||||
|  */ | ||||
| function _recaptcha_qsencode ($data) { | ||||
|         $req = ""; | ||||
|         foreach ( $data as $key => $value ) | ||||
|                 $req .= $key . '=' . urlencode( stripslashes($value) ) . '&'; | ||||
|  | ||||
|         // Cut the last '&' | ||||
|         $req=substr($req,0,strlen($req)-1); | ||||
|         return $req; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Submits an HTTP POST to a reCAPTCHA server | ||||
|  * @param string $host | ||||
|  * @param string $path | ||||
|  * @param array $data | ||||
|  * @param int port | ||||
|  * @return array response | ||||
|  */ | ||||
| function _recaptcha_http_post($host, $path, $data, $port = 80) { | ||||
|  | ||||
|         $req = _recaptcha_qsencode ($data); | ||||
|  | ||||
|         $http_request  = "POST $path HTTP/1.0\r\n"; | ||||
|         $http_request .= "Host: $host\r\n"; | ||||
|         $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n"; | ||||
|         $http_request .= "Content-Length: " . strlen($req) . "\r\n"; | ||||
|         $http_request .= "User-Agent: reCAPTCHA/PHP\r\n"; | ||||
|         $http_request .= "\r\n"; | ||||
|         $http_request .= $req; | ||||
|  | ||||
|         $response = ''; | ||||
|         if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) { | ||||
|                 die ('Could not open socket'); | ||||
|         } | ||||
|  | ||||
|         fwrite($fs, $http_request); | ||||
|  | ||||
|         while ( !feof($fs) ) | ||||
|                 $response .= fgets($fs, 1160); // One TCP-IP packet | ||||
|         fclose($fs); | ||||
|         $response = explode("\r\n\r\n", $response, 2); | ||||
|  | ||||
|         return $response; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Gets the challenge HTML (javascript and non-javascript version). | ||||
|  * This is called from the browser, and the resulting reCAPTCHA HTML widget | ||||
|  * is embedded within the HTML form it was called from. | ||||
|  * @param string $pubkey A public key for reCAPTCHA | ||||
|  * @param string $error The error given by reCAPTCHA (optional, default is null) | ||||
|  * @param boolean $use_ssl Should the request be made over ssl? (optional, default is false) | ||||
|  | ||||
|  * @return string - The HTML to be embedded in the user's form. | ||||
|  */ | ||||
| function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false) | ||||
| { | ||||
| 	if ($pubkey == null || $pubkey == '') { | ||||
| 		die ("To use reCAPTCHA you must get an API key from <a href='http://recaptcha.net/api/getkey'>http://recaptcha.net/api/getkey</a>"); | ||||
| 	} | ||||
| 	 | ||||
| 	if ($use_ssl) { | ||||
|                 $server = RECAPTCHA_API_SECURE_SERVER; | ||||
|         } else { | ||||
|                 $server = RECAPTCHA_API_SERVER; | ||||
|         } | ||||
|  | ||||
|         $errorpart = ""; | ||||
|         if ($error) { | ||||
|            $errorpart = "&error=" . $error; | ||||
|         } | ||||
|         return '<script type="text/javascript" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '"></script> | ||||
|  | ||||
| 	<noscript> | ||||
|   		<iframe src="'. $server . '/noscript?k=' . $pubkey . $errorpart . '" height="300" width="500" frameborder="0"></iframe><br/> | ||||
|   		<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea> | ||||
|   		<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/> | ||||
| 	</noscript>'; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * A ReCaptchaResponse is returned from recaptcha_check_answer() | ||||
|  */ | ||||
| class ReCaptchaResponse { | ||||
|         var $is_valid; | ||||
|         var $error; | ||||
| } | ||||
|  | ||||
|  | ||||
| /** | ||||
|   * Calls an HTTP POST function to verify if the user's guess was correct | ||||
|   * @param string $privkey | ||||
|   * @param string $remoteip | ||||
|   * @param string $challenge | ||||
|   * @param string $response | ||||
|   * @param array $extra_params an array of extra variables to post to the server | ||||
|   * @return ReCaptchaResponse | ||||
|   */ | ||||
| function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array()) | ||||
| { | ||||
| 	if ($privkey == null || $privkey == '') { | ||||
| 		die ("To use reCAPTCHA you must get an API key from <a href='http://recaptcha.net/api/getkey'>http://recaptcha.net/api/getkey</a>"); | ||||
| 	} | ||||
|  | ||||
| 	if ($remoteip == null || $remoteip == '') { | ||||
| 		die ("For security reasons, you must pass the remote ip to reCAPTCHA"); | ||||
| 	} | ||||
|  | ||||
| 	 | ||||
| 	 | ||||
|         //discard spam submissions | ||||
|         if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) { | ||||
|                 $recaptcha_response = new ReCaptchaResponse(); | ||||
|                 $recaptcha_response->is_valid = false; | ||||
|                 $recaptcha_response->error = 'incorrect-captcha-sol'; | ||||
|                 return $recaptcha_response; | ||||
|         } | ||||
|  | ||||
|         $response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/verify", | ||||
|                                           array ( | ||||
|                                                  'privatekey' => $privkey, | ||||
|                                                  'remoteip' => $remoteip, | ||||
|                                                  'challenge' => $challenge, | ||||
|                                                  'response' => $response | ||||
|                                                  ) + $extra_params | ||||
|                                           ); | ||||
|  | ||||
|         $answers = explode ("\n", $response [1]); | ||||
|         $recaptcha_response = new ReCaptchaResponse(); | ||||
|  | ||||
|         if (trim ($answers [0]) == 'true') { | ||||
|                 $recaptcha_response->is_valid = true; | ||||
|         } | ||||
|         else { | ||||
|                 $recaptcha_response->is_valid = false; | ||||
|                 $recaptcha_response->error = $answers [1]; | ||||
|         } | ||||
|         return $recaptcha_response; | ||||
|  | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * gets a URL where the user can sign up for reCAPTCHA. If your application | ||||
|  * has a configuration page where you enter a key, you should provide a link | ||||
|  * using this function. | ||||
|  * @param string $domain The domain where the page is hosted | ||||
|  * @param string $appname The name of your application | ||||
|  */ | ||||
| function recaptcha_get_signup_url ($domain = null, $appname = null) { | ||||
| 	return "http://recaptcha.net/api/getkey?" .  _recaptcha_qsencode (array ('domain' => $domain, 'app' => $appname)); | ||||
| } | ||||
|  | ||||
| function _recaptcha_aes_pad($val) { | ||||
| 	$block_size = 16; | ||||
| 	$numpad = $block_size - (strlen ($val) % $block_size); | ||||
| 	return str_pad($val, strlen ($val) + $numpad, chr($numpad)); | ||||
| } | ||||
|  | ||||
| /* Mailhide related code */ | ||||
|  | ||||
| function _recaptcha_aes_encrypt($val,$ky) { | ||||
| 	if (! function_exists ("mcrypt_encrypt")) { | ||||
| 		die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed."); | ||||
| 	} | ||||
| 	$mode=MCRYPT_MODE_CBC;    | ||||
| 	$enc=MCRYPT_RIJNDAEL_128; | ||||
| 	$val=_recaptcha_aes_pad($val); | ||||
| 	return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); | ||||
| } | ||||
|  | ||||
|  | ||||
| function _recaptcha_mailhide_urlbase64 ($x) { | ||||
| 	return strtr(base64_encode ($x), '+/', '-_'); | ||||
| } | ||||
|  | ||||
| /* gets the reCAPTCHA Mailhide url for a given email, public key and private key */ | ||||
| function recaptcha_mailhide_url($pubkey, $privkey, $email) { | ||||
| 	if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) { | ||||
| 		die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " . | ||||
| 		     "you can do so at <a href='http://mailhide.recaptcha.net/apikey'>http://mailhide.recaptcha.net/apikey</a>"); | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	$ky = pack('H*', $privkey); | ||||
| 	$cryptmail = _recaptcha_aes_encrypt ($email, $ky); | ||||
| 	 | ||||
| 	return "http://mailhide.recaptcha.net/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * gets the parts of the email to expose to the user. | ||||
|  * eg, given johndoe@example,com return ["john", "example.com"]. | ||||
|  * the email is then displayed as john...@example.com | ||||
|  */ | ||||
| function _recaptcha_mailhide_email_parts ($email) { | ||||
| 	$arr = preg_split("/@/", $email ); | ||||
|  | ||||
| 	if (strlen ($arr[0]) <= 4) { | ||||
| 		$arr[0] = substr ($arr[0], 0, 1); | ||||
| 	} else if (strlen ($arr[0]) <= 6) { | ||||
| 		$arr[0] = substr ($arr[0], 0, 3); | ||||
| 	} else { | ||||
| 		$arr[0] = substr ($arr[0], 0, 4); | ||||
| 	} | ||||
| 	return $arr; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Gets html to display an email address given a public an private key. | ||||
|  * to get a key, go to: | ||||
|  * | ||||
|  * http://mailhide.recaptcha.net/apikey | ||||
|  */ | ||||
| function recaptcha_mailhide_html($pubkey, $privkey, $email) { | ||||
| 	$emailparts = _recaptcha_mailhide_email_parts ($email); | ||||
| 	$url = recaptcha_mailhide_url ($pubkey, $privkey, $email); | ||||
| 	 | ||||
| 	return htmlentities($emailparts[0]) . "<a href='" . htmlentities ($url) . | ||||
| 		"' onclick=\"window.open('" . htmlentities ($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>@" . htmlentities ($emailparts [1]); | ||||
|  | ||||
| } | ||||
|  | ||||
|  | ||||
| ?> | ||||
| @@ -317,6 +317,9 @@ class MailerDaemon | ||||
|         } else if ($parsed->ctype_primary == 'text' | ||||
|             && $parsed->ctype_secondary=='plain') { | ||||
|             $msg = $parsed->body; | ||||
|             if(strtolower($parsed->ctype_parameters['charset']) != "utf-8"){ | ||||
|                 $msg = utf8_encode($msg); | ||||
|             } | ||||
|         }else if(!empty($parsed->body)){ | ||||
|             if(common_config('attachments', 'uploads')){ | ||||
|                 //only save attachments if uploads are enabled | ||||
|   | ||||
							
								
								
									
										36
									
								
								scripts/sessiongc.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								scripts/sessiongc.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| #!/usr/bin/env php | ||||
| <?php | ||||
| /* | ||||
|  * Laconica - a distributed open-source microblogging tool | ||||
|  * Copyright (C) 2008, 2009, Control Yourself, Inc. | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Affero General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU Affero General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); | ||||
|  | ||||
| $helptext = <<<END_OF_GC_HELP | ||||
| sessiongc.php | ||||
|  | ||||
| Delete old sessions from the server | ||||
|  | ||||
| END_OF_GC_HELP; | ||||
|  | ||||
| require_once INSTALLDIR.'/scripts/commandline.inc'; | ||||
|  | ||||
| $maxlifetime = ini_get('session.gc_maxlifetime'); | ||||
|  | ||||
| print "Deleting sessions older than $maxlifetime seconds.\n"; | ||||
|  | ||||
| Session::gc($maxlifetime); | ||||
		Reference in New Issue
	
	Block a user