diff --git a/actions/groupsearch.php b/actions/groupsearch.php index 9b0026db94..109a53ce11 100644 --- a/actions/groupsearch.php +++ b/actions/groupsearch.php @@ -1,9 +1,4 @@ terms = array_map('preg_quote', + $this->terms = array_map('preg_quote', array_map('htmlspecialchars', $terms)); $this->pattern = '/('.implode('|',$terms).')/i'; } - + function highlight($text) { return preg_replace($this->pattern, '\\1', htmlspecialchars($text)); diff --git a/actions/noticesearch.php b/actions/noticesearch.php index 83e59dd9ae..9058cf53c3 100644 --- a/actions/noticesearch.php +++ b/actions/noticesearch.php @@ -103,7 +103,7 @@ class NoticesearchAction extends SearchAction function showResults($q, $page) { $notice = new Notice(); - $q = strtolower($q); + $search_engine = $notice->getSearchEngine('identica_notices'); $search_engine->set_sort_mode('chron'); // Ask for an extra to see if there's more. @@ -122,9 +122,10 @@ class NoticesearchAction extends SearchAction $cnt = $nl->show(); - $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, - $this->page, 'noticesearch', array('q' => $q)); + $this->pagination($page > 1, $cnt > NOTICES_PER_PAGE, + $page, 'noticesearch', array('q' => $q)); } + function isReadOnly() { return true; diff --git a/actions/noticesearchrss.php b/actions/noticesearchrss.php index 0f98ed04bb..ba5276d06e 100644 --- a/actions/noticesearchrss.php +++ b/actions/noticesearchrss.php @@ -62,9 +62,6 @@ class NoticesearchrssAction extends Rss10Action $notice = new Notice(); - # lcase it for comparison - $q = strtolower($q); - $search_engine = $notice->getSearchEngine('identica_notices'); $search_engine->set_sort_mode('chron'); diff --git a/actions/peoplesearch.php b/actions/peoplesearch.php index 14177fcf0d..9e515ade1a 100644 --- a/actions/peoplesearch.php +++ b/actions/peoplesearch.php @@ -63,13 +63,13 @@ class PeoplesearchAction extends SearchAction $profile = new Profile(); - # lcase it for comparison - $q = strtolower($q); + // lcase it for comparison + // $q = strtolower($q); $search_engine = $profile->getSearchEngine('identica_people'); $search_engine->set_sort_mode('chron'); - # Ask for an extra to see if there's more. + // Ask for an extra to see if there's more. $search_engine->limit((($page-1)*PROFILES_PER_PAGE), PROFILES_PER_PAGE + 1); if (false === $search_engine->query($q)) { $cnt = 0; diff --git a/actions/public.php b/actions/public.php index a20ae40321..9b22e0a2ce 100644 --- a/actions/public.php +++ b/actions/public.php @@ -207,9 +207,14 @@ class PublicAction extends Action function showAnonymousMessage() { - $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . - 'based on the Free Software [Laconica](http://laconi.ca/) tool. ' . - '[Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ([Read more](%%doc.help%%))'); + if (! (common_config('site','closed') || common_config('site','inviteonly'))) { + $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . + 'based on the Free Software [Laconica](http://laconi.ca/) tool. ' . + '[Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ([Read more](%%doc.help%%))'); + } else { + $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . + 'based on the Free Software [Laconica](http://laconi.ca/) tool.'); + } $this->elementStart('div', array('id' => 'anon_notice')); $this->raw(common_markup_to_html($m)); $this->elementEnd('div'); diff --git a/actions/recoverpassword.php b/actions/recoverpassword.php index eeb6b2516c..620fe7eb8e 100644 --- a/actions/recoverpassword.php +++ b/actions/recoverpassword.php @@ -181,13 +181,21 @@ class RecoverpasswordAction extends Action function showRecoverForm() { $this->elementStart('form', array('method' => 'post', - 'id' => 'recoverpassword', + 'id' => 'form_password_recover', + 'class' => 'form_settings', 'action' => common_local_url('recoverpassword'))); + $this->elementStart('fieldset'); + $this->element('legend', null, _('Password recover')); + $this->elementStart('ul', 'form_data'); + $this->elementStart('li'); $this->input('nicknameoremail', _('Nickname or email'), $this->trimmed('nicknameoremail'), _('Your nickname on this server, ' . 'or your registered email address.')); + $this->elementEnd('li'); + $this->elementEnd('ul'); $this->submit('recover', _('Recover')); + $this->elementEnd('fieldset'); $this->elementEnd('form'); } @@ -213,14 +221,24 @@ class RecoverpasswordAction extends Action function showResetForm() { $this->elementStart('form', array('method' => 'post', - 'id' => 'recoverpassword', + 'id' => 'form_password_change', + 'class' => 'form_settings', 'action' => common_local_url('recoverpassword'))); + $this->elementStart('fieldset'); + $this->element('legend', null, _('Password change')); $this->hidden('token', common_session_token()); + $this->elementStart('ul', 'form_data'); + $this->elementStart('li'); $this->password('newpassword', _('New password'), _('6 or more characters, and don\'t forget it!')); + $this->elementEnd('li'); + $this->elementStart('li'); $this->password('confirm', _('Confirm'), _('Same as password above')); + $this->elementEnd('li'); + $this->elementEnd('ul'); $this->submit('reset', _('Reset')); + $this->elementEnd('fieldset'); $this->elementEnd('form'); } diff --git a/actions/showgroup.php b/actions/showgroup.php index b6022840bf..58cc7a97cd 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -390,11 +390,18 @@ class ShowgroupAction extends Action function showAnonymousMessage() { - $m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . - 'based on the Free Software [Laconica](http://laconi.ca/) tool. Its members share ' . - 'short messages about their life and interests. '. - '[Join now](%%%%action.register%%%%) to become part of this group and many more! ([Read more](%%%%doc.help%%%%))'), + if (!(common_config('site','closed') || common_config('site','inviteonly'))) { + $m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . + 'based on the Free Software [Laconica](http://laconi.ca/) tool. Its members share ' . + 'short messages about their life and interests. '. + '[Join now](%%%%action.register%%%%) to become part of this group and many more! ([Read more](%%%%doc.help%%%%))'), $this->group->nickname); + } else { + $m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . + 'based on the Free Software [Laconica](http://laconi.ca/) tool. Its members share ' . + 'short messages about their life and interests. '), + $this->group->nickname); + } $this->elementStart('div', array('id' => 'anon_notice')); $this->raw(common_markup_to_html($m)); $this->elementEnd('div'); diff --git a/actions/shownotice.php b/actions/shownotice.php index d5f35cd84b..ccae49bb3e 100644 --- a/actions/shownotice.php +++ b/actions/shownotice.php @@ -177,10 +177,17 @@ class ShownoticeAction extends Action { parent::handle($args); - $this->showPage(); + if ($this->notice->is_local == 0) { + if (!empty($this->notice->url)) { + common_redirect($this->notice->url, 301); + } else if (!empty($this->notice->uri) && preg_match('/^https?:/', $this->notice->uri)) { + common_redirect($this->notice->uri, 301); + } + } else { + $this->showPage(); + } } - /** * Don't show local navigation * @@ -191,7 +198,6 @@ class ShownoticeAction extends Action { } - /** * Fill the content area of the page * @@ -208,8 +214,6 @@ class ShownoticeAction extends Action $this->elementEnd('ul'); } - - /** * Don't show page notice * @@ -220,7 +224,6 @@ class ShownoticeAction extends Action { } - /** * Don't show aside * @@ -230,7 +233,6 @@ class ShownoticeAction extends Action function showAside() { } - /** * Extra content * diff --git a/actions/showstream.php b/actions/showstream.php index 65482167e1..b83f45d53b 100644 --- a/actions/showstream.php +++ b/actions/showstream.php @@ -539,10 +539,16 @@ class ShowstreamAction extends Action function showAnonymousMessage() { - $m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . - 'based on the Free Software [Laconica](http://laconi.ca/) tool. ' . - '[Join now](%%%%action.register%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'), - $this->user->nickname, $this->user->nickname); + if (!(common_config('site','closed') || common_config('site','inviteonly'))) { + $m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . + 'based on the Free Software [Laconica](http://laconi.ca/) tool. ' . + '[Join now](%%%%action.register%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'), + $this->user->nickname, $this->user->nickname); + } else { + $m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' . + 'based on the Free Software [Laconica](http://laconi.ca/) tool. '), + $this->user->nickname, $this->user->nickname); + } $this->elementStart('div', array('id' => 'anon_notice')); $this->raw(common_markup_to_html($m)); $this->elementEnd('div'); diff --git a/apple-touch-icon.png b/apple-touch-icon.png new file mode 100644 index 0000000000..d129298d4a Binary files /dev/null and b/apple-touch-icon.png differ diff --git a/classes/Notice.php b/classes/Notice.php index 3087e39a78..44a6aeb986 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -799,4 +799,98 @@ class Notice extends Memcached_DataObject } } } + + function asAtomEntry($namespace=false, $source=false) + { + $profile = $this->getProfile(); + + $xs = new XMLStringer(true); + + if ($namespace) { + $attrs = array('xmlns' => 'http://www.w3.org/2005/Atom', + 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0'); + } else { + $attrs = array(); + } + + $xs->elementStart('entry', $attrs); + + if ($source) { + $xs->elementStart('source'); + $xs->element('title', null, $profile->nickname . " - " . common_config('site', 'name')); + $xs->element('link', array('href' => $profile->profileurl)); + $user = User::staticGet('id', $profile->id); + if (!empty($user)) { + $atom_feed = common_local_url('api', + array('apiaction' => 'statuses', + 'method' => 'user_timeline', + 'argument' => $profile->nickname.'.atom')); + $xs->element('link', array('rel' => 'self', + 'type' => 'application/atom+xml', + 'href' => $profile->profileurl)); + $xs->element('link', array('rel' => 'license', + 'href' => common_config('license', 'url'))); + } + + $xs->element('icon', null, $profile->avatarUrl(AVATAR_PROFILE_SIZE)); + } + + $xs->elementStart('author'); + $xs->element('name', null, $profile->nickname); + $xs->element('uri', null, $profile->profileurl); + $xs->elementEnd('author'); + + if ($source) { + $xs->elementEnd('source'); + } + + $xs->element('title', null, $this->content); + $xs->element('summary', null, $this->content); + + $xs->element('link', array('rel' => 'alternate', + 'href' => $this->bestUrl())); + + $xs->element('id', null, $this->uri); + + $xs->element('published', null, common_date_w3dtf($this->created)); + $xs->element('updated', null, common_date_w3dtf($this->modified)); + + if ($this->reply_to) { + $reply_notice = Notice::staticGet('id', $this->reply_to); + if (!empty($reply_notice)) { + $xs->element('link', array('rel' => 'related', + 'href' => $reply_notice->bestUrl())); + $xs->element('thr:in-reply-to', + array('ref' => $reply_notice->uri, + 'href' => $reply_notice->bestUrl())); + } + } + + $xs->element('content', array('type' => 'html'), $this->rendered); + + $tag = new Notice_tag(); + $tag->notice_id = $this->id; + if ($tag->find()) { + while ($tag->fetch()) { + $xs->element('category', array('term' => $tag->tag)); + } + } + $tag->free(); + + $xs->elementEnd('entry'); + + return $xs->getString(); + } + + function bestUrl() + { + if (!empty($this->url)) { + return $this->url; + } else if (!empty($this->uri) && preg_match('/^https?:/', $this->uri)) { + return $this->uri; + } else { + return common_local_url('shownotice', + array('notice' => $this->id)); + } + } } diff --git a/db/notice_source.sql b/db/notice_source.sql index 5e2d413c00..d28a09383f 100644 --- a/db/notice_source.sql +++ b/db/notice_source.sql @@ -19,6 +19,7 @@ VALUES ('identichat','identichat','http://identichat.prosody.im/', now()), ('identitwitch','IdentiTwitch','http://richfish.org/identitwitch/', now()), ('mbpidgin','mbpidgin','http://code.google.com/p/microblog-purple/', now()), + ('Mobidentica', 'Mobidentica', 'http://www.substanceofcode.com/software/mobidentica/', now()), ('moconica','Moconica','http://moconica.com/', now()), ('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()), ('posty','Posty','http://spreadingfunkyness.com/posty/', now()), @@ -44,4 +45,4 @@ VALUES ('twitux','Twitux','http://live.gnome.org/DanielMorales/Twitux', now()), ('twitvim','TwitVim','http://vim.sourceforge.net/scripts/script.php?script_id=2204', now()), ('urfastr','urfastr','http://urfastr.net/', now()), - ('adium', 'Adium', 'http://www.adiumx.com/', now())); + ('adium', 'Adium', 'http://www.adiumx.com/', now()); diff --git a/js/util.js b/js/util.js index 3ad0386122..81139744ff 100644 --- a/js/util.js +++ b/js/util.js @@ -161,6 +161,7 @@ $(document).ready(function(){ $("#form_notice").addClass("warning"); return false; } + $("#form_notice").addClass("processing"); $("#notice_action-submit").attr("disabled", "disabled"); $("#notice_action-submit").addClass("disabled"); return true; @@ -179,6 +180,7 @@ $(document).ready(function(){ NoticeHover(); NoticeReply(); } + $("#form_notice").removeClass("processing"); $("#notice_action-submit").removeAttr("disabled"); $("#notice_action-submit").removeClass("disabled"); } diff --git a/lib/action.php b/lib/action.php index 975c2bfcb8..f0baa062c2 100644 --- a/lib/action.php +++ b/lib/action.php @@ -112,6 +112,7 @@ class Action extends HTMLOutputter // lawsuit // XXX: attributes (profile?) $this->elementStart('head'); $this->showTitle(); + $this->showShortcutIcon(); $this->showStylesheets(); $this->showScripts(); $this->showOpenSearch(); @@ -147,6 +148,32 @@ class Action extends HTMLOutputter // lawsuit return _("Untitled page"); } + /** + * Show themed shortcut icon + * + * @return nothing + */ + function showShortcutIcon() + { + if (is_readable(INSTALLDIR . '/theme/' . common_config('site', 'theme') . '/favicon.ico')) { + $this->element('link', array('rel' => 'shortcut icon', + 'href' => theme_path('favicon.ico'))); + } else { + $this->element('link', array('rel' => 'shortcut icon', + 'href' => common_path('favicon.ico'))); + } + + if (common_config('site', 'mobile')) { + if (is_readable(INSTALLDIR . '/theme/' . common_config('site', 'theme') . '/apple-touch-icon.png')) { + $this->element('link', array('rel' => 'apple-touch-icon', + 'href' => theme_path('apple-touch-icon.png'))); + } else { + $this->element('link', array('rel' => 'apple-touch-icon', + 'href' => common_path('apple-touch-icon.png'))); + } + } + } + /** * Show stylesheets * diff --git a/lib/jabber.php b/lib/jabber.php index 3cd3b0d37e..7d584ad016 100644 --- a/lib/jabber.php +++ b/lib/jabber.php @@ -163,50 +163,25 @@ function jabber_send_notice($to, $notice) function jabber_format_entry($profile, $notice) { - // FIXME: notice url might be remote + $entry = $notice->asAtomEntry(true, true); - $noticeurl = common_local_url('shownotice', - array('notice' => $notice->id)); - - $msg = jabber_format_notice($profile, $notice); - - $self_url = common_local_url('userrss', array('nickname' => $profile->nickname)); - - $entry = "\n\n"; - $entry .= "\n"; - $entry .= "" . $profile->nickname . " - " . common_config('site', 'name') . "\n"; - $entry .= "\n"; - $entry .= "\n"; - $entry .= "" . $profile->nickname . "\n"; - $entry .= "" . $profile->avatarUrl(AVATAR_PROFILE_SIZE) . "\n"; - $entry .= "\n"; - $entry .= "" . htmlspecialchars($msg) . "\n"; - $entry .= "" . htmlspecialchars($msg) . "\n"; - $entry .= "\n"; - $entry .= "". $notice->uri . "\n"; - $entry .= "".common_date_w3dtf($notice->created)."\n"; - $entry .= "".common_date_w3dtf($notice->modified)."\n"; - if ($notice->reply_to) { - $replyurl = common_local_url('shownotice', - array('notice' => $notice->reply_to)); - $entry .= "\n"; + $xs = new XMLStringer(); + $xs->elementStart('html', array('xmlns' => 'http://jabber.org/protocol/xhtml-im')); + $xs->elementStart('body', array('xmlns' => 'http://www.w3.org/1999/xhtml')); + $xs->element('a', array('href' => $profile->profileurl), + $profile->nickname); + $xs->text(": "); + if (!empty($notice->rendered)) { + $xs->raw($notice->rendered); + } else { + $xs->raw(common_render_content($notice->content, $notice)); } - $entry .= "\n"; + $xs->elementEnd('body'); + $xs->elementEnd('html'); - $html = "\n\n"; - $html .= "\n"; - $html .= "".$profile->nickname.": "; - $html .= ($notice->rendered) ? $notice->rendered : common_render_content($notice->content, $notice); - $html .= "\n\n"; - $html .= "\n\n"; + $html = $xs->getString(); - $address = "\n"; - $address .= "
\n"; - $address .= "\n"; - - // FIXME: include a pubsub event, too. - - return $html . $entry . $address; + return $html . ' ' . $entry; } /** diff --git a/lib/language.php b/lib/language.php index 6791df699d..cd6498d30b 100644 --- a/lib/language.php +++ b/lib/language.php @@ -115,7 +115,7 @@ function get_all_languages() { 'he' => array('q' => 0.5, 'lang' => 'he_IL', 'name' => 'Hebrew', 'direction' => 'rtl'), 'it' => array('q' => 1, 'lang' => 'it_IT', 'name' => 'Italian', 'direction' => 'ltr'), 'jp' => array('q' => 0.5, 'lang' => 'ja_JP', 'name' => 'Japanese', 'direction' => 'ltr'), - 'ko' => array('q' => 0.9, 'lang' => 'ko', 'name' => 'Korean', 'direction' => 'ltr'), + 'ko' => array('q' => 0.9, 'lang' => 'ko_KR', 'name' => 'Korean', 'direction' => 'ltr'), 'mk' => array('q' => 0.5, 'lang' => 'mk_MK', 'name' => 'Macedonian', 'direction' => 'ltr'), 'nb' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'), 'no' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'), diff --git a/lib/logingroupnav.php b/lib/logingroupnav.php index fd909581f4..f23985f3ab 100644 --- a/lib/logingroupnav.php +++ b/lib/logingroupnav.php @@ -70,16 +70,16 @@ class LoginGroupNav extends Widget function show() { // action => array('prompt', 'title') - $menu = - array('login' => - array(_('Login'), - _('Login with a username and password')), - 'register' => - array(_('Register'), - _('Sign up for a new account')), - 'openidlogin' => - array(_('OpenID'), - _('Login or register with OpenID'))); + $menu = array(); + + $menu['login'] = array(_('Login'), + _('Login with a username and password')); + if (!(common_config('site','closed') || common_config('site','inviteonly'))) { + $menu['register'] = array(_('Register'), + _('Sign up for a new account')); + } + $menu['openidlogin'] = array(_('OpenID'), + _('Login or register with OpenID')); $action_name = $this->action->trimmed('action'); $this->action->elementStart('ul', array('class' => 'nav')); diff --git a/lib/mail.php b/lib/mail.php index dde7571ebe..27a1d99dcb 100644 --- a/lib/mail.php +++ b/lib/mail.php @@ -554,17 +554,19 @@ function mail_notify_fave($other, $user, $notice) $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" . + "The URL of your notice is:\n\n" . "%3\$s\n\n" . - "You can see the list of %1\$s's favorites here:\n\n" . + "The text of your notice is:\n\n" . "%4\$s\n\n" . + "You can see the list of %1\$s's favorites here:\n\n" . + "%5\$s\n\n" . "Faithfully yours,\n" . - "%5\$s\n"), + "%6\$s\n"), $bestname, common_exact_date($notice->created), common_local_url('shownotice', array('notice' => $notice->id)), + $notice->content, common_local_url('showfavorites', array('nickname' => $user->nickname)), common_config('site', 'name')); diff --git a/lib/messageform.php b/lib/messageform.php index f415083057..b8878ec1f9 100644 --- a/lib/messageform.php +++ b/lib/messageform.php @@ -132,20 +132,14 @@ class MessageForm extends Form $mutual_users->free(); unset($mutual_users); - $this->out->elementStart('ul', 'form_data'); - $this->out->elementStart('li', array('id' => 'notice_to')); $this->out->dropdown('to', _('To'), $mutual, null, false, ($this->to) ? $this->to->id : null); - $this->out->elementEnd('li'); - $this->out->elementStart('li', array('id' => 'notice_text')); $this->out->element('textarea', array('id' => 'notice_data-text', 'cols' => 35, 'rows' => 4, 'name' => 'content'), ($this->content) ? $this->content : ''); - $this->out->elementEnd('li'); - $this->out->elementEnd('ul'); } /** @@ -156,14 +150,10 @@ class MessageForm extends Form function formActions() { - $this->out->elementStart('ul', 'form_actions'); - $this->out->elementStart('li', array('id' => 'notice_submit')); $this->out->element('input', array('id' => 'notice_action-submit', 'class' => 'submit', 'name' => 'message_send', 'type' => 'submit', 'value' => _('Send'))); - $this->out->elementEnd('li'); - $this->out->elementEnd('ul'); } } diff --git a/lib/noticeform.php b/lib/noticeform.php index 0c991c9695..606b5d028e 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -134,9 +134,6 @@ class NoticeForm extends Form function formData() { - - $this->out->elementStart('ul', 'form_data'); - $this->out->elementStart('li', array('id' => 'notice_text')); $this->out->element('label', array('for' => 'notice_data-text'), sprintf(_('What\'s up, %s?'), $this->user->nickname)); // XXX: vary by defined max size @@ -145,8 +142,6 @@ class NoticeForm extends Form 'rows' => 4, 'name' => 'status_textarea'), ($this->content) ? $this->content : ''); - $this->out->elementEnd('li'); - $this->out->elementEnd('ul'); $this->out->elementStart('dl', 'form_note'); $this->out->element('dt', null, _('Available characters')); @@ -168,14 +163,10 @@ class NoticeForm extends Form function formActions() { - $this->out->elementStart('ul', 'form_actions'); - $this->out->elementStart('li', array('id' => 'notice_submit')); $this->out->element('input', array('id' => 'notice_action-submit', 'class' => 'submit', 'name' => 'status_submit', 'type' => 'submit', 'value' => _('Send'))); - $this->out->elementEnd('li'); - $this->out->elementEnd('ul'); } } diff --git a/lib/ping.php b/lib/ping.php index 32c0b9806a..3de541e9aa 100644 --- a/lib/ping.php +++ b/lib/ping.php @@ -1,7 +1,7 @@ is_local) { - return; + return true; } - + # Array of servers, URL => type $notify = common_config('ping', 'notify'); $profile = $notice->getProfile(); $tags = ping_notice_tags($notice); - + foreach ($notify as $notify_url => $type) { switch ($type) { case 'xmlrpc': case 'extended': $req = xmlrpc_encode_request('weblogUpdates.ping', array($profile->nickname, # site name - common_local_url('showstream', + common_local_url('showstream', array('nickname' => $profile->nickname)), common_local_url('shownotice', array('notice' => $notice->id)), - common_local_url('userrss', + common_local_url('userrss', array('nickname' => $profile->nickname)), $tags)); - - # We re-use this tool's fetcher, since it's pretty good - - $fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); - if (!$fetcher) { - common_log(LOG_WARNING, 'Failed to initialize Yadis fetcher.', __FILE__); - return false; - } - - $result = $fetcher->post($notify_url, - $req); - + $context = stream_context_create(array('http' => array('method' => "POST", + 'header' => + "Content-Type: text/xml\r\n". + "User-Agent: Laconica/".LACONICA_VERSION."\r\n", + 'content' => $req))); + $file = file_get_contents($notify_url, false, $context); + + if ($file === false || mb_strlen($file) == 0) { + common_log(LOG_WARNING, + "XML-RPC empty results for ping ($notify_url, $notice->id) "); + continue; + } + + $response = xmlrpc_decode($file); + + if (xmlrpc_is_fault($response)) { + common_log(LOG_WARNING, + "XML-RPC error for ping ($notify_url, $notice->id) ". + "$response[faultString] ($response[faultCode])"); + } else { + common_log(LOG_INFO, + "Ping success for $notify_url $notice->id"); + } + break; + case 'get': - case 'post': + case 'post': + $args = array('name' => $profile->nickname, + 'url' => common_local_url('showstream', + array('nickname' => $profile->nickname)), + 'changesURL' => common_local_url('userrss', + array('nickname' => $profile->nickname))); + + $fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); + + if ($type === 'get') { + $result = $fetcher->get($notify_url . '?' . http_build_query($args), + array('User-Agent: Laconica/'.LACONICA_VERSION)); + } else { + $result = $fetcher->post($notify_url, + http_build_query($args), + array('User-Agent: Laconica/'.LACONICA_VERSION)); + } + if ($result->status != '200') { + common_log(LOG_WARNING, + "Ping error for '$notify_url' ($notice->id): ". + "$result->body"); + } else { + common_log(LOG_INFO, + "Ping success for '$notify_url' ($notice->id): ". + "'$result->body'"); + } + break; + default: common_log(LOG_WARNING, 'Unknown notify type for ' . $notify_url . ': ' . $type); - } + } } + + return true; } - + function ping_notice_tags($notice) { $tag = new Notice_tag(); $tag->notice_id = $notice->id; diff --git a/lib/profilelist.php b/lib/profilelist.php index 766189ab4c..a4cc235552 100644 --- a/lib/profilelist.php +++ b/lib/profilelist.php @@ -89,7 +89,7 @@ class ProfileList extends Widget 'id' => 'profile-' . $this->profile->id)); $user = common_current_user(); - $is_own = !is_null($user) && isset($this->user) && ($user->id === $this->user->id); + $is_own = !is_null($user) && isset($this->owner) && ($user->id === $this->owner->id); $this->out->elementStart('div', 'entity_profile vcard'); @@ -109,7 +109,7 @@ class ProfileList extends Widget $this->out->elementEnd('span'); $this->out->elementEnd('a'); - if ($this->profile->fullname !== '') { + if (!empty($this->profile->fullname)) { $this->out->elementStart('dl', 'entity_fn'); $this->out->element('dt', null, 'Full name'); $this->out->elementStart('dd'); @@ -119,7 +119,7 @@ class ProfileList extends Widget $this->out->elementEnd('dd'); $this->out->elementEnd('dl'); } - if ($this->profile->location !== '') { + if (!empty($this->profile->location)) { $this->out->elementStart('dl', 'entity_location'); $this->out->element('dt', null, _('Location')); $this->out->elementStart('dd', 'label'); @@ -127,7 +127,7 @@ class ProfileList extends Widget $this->out->elementEnd('dd'); $this->out->elementEnd('dl'); } - if ($this->profile->homepage !== '') { + if (!empty($this->profile->homepage)) { $this->out->elementStart('dl', 'entity_url'); $this->out->element('dt', null, _('URL')); $this->out->elementStart('dd'); @@ -138,7 +138,7 @@ class ProfileList extends Widget $this->out->elementEnd('dd'); $this->out->elementEnd('dl'); } - if ($this->profile->bio !== '') { + if (!empty($this->profile->bio)) { $this->out->elementStart('dl', 'entity_note'); $this->out->element('dt', null, _('Note')); $this->out->elementStart('dd', 'note'); @@ -194,11 +194,12 @@ class ProfileList extends Widget $this->out->elementStart('ul'); - if (!$is_own) { - # XXX: special-case for user looking at own - # subscriptions page + // Is this a logged-in user, looking at someone else's + // profile? + + if (!empty($user) && $this->profile->id != $user->id) { $this->out->elementStart('li', 'entity_subscribe'); - if (!is_null($user) && $user->isSubscribed($this->profile)) { + if ($user->isSubscribed($this->profile)) { $usf = new UnsubscribeForm($this->out, $this->profile); $usf->show(); } else { @@ -207,6 +208,9 @@ class ProfileList extends Widget } $this->out->elementEnd('li'); $this->out->elementStart('li', 'entity_block'); + if ($user->id == $this->owner->id) { + $this->showBlockForm(); + } $this->out->elementEnd('li'); } diff --git a/lib/router.php b/lib/router.php index e39dc217a3..ae5b5e16bd 100644 --- a/lib/router.php +++ b/lib/router.php @@ -68,8 +68,8 @@ class Router } } - function initialize() { - + function initialize() + { $m = Net_URL_Mapper::getInstance(); // In the "root" @@ -136,10 +136,17 @@ class Router foreach (array('group', 'people', 'notice') as $s) { $m->connect('search/'.$s, array('action' => $s.'search')); - $m->connect('search/'.$s.'?q=:q', array('action' => $s.'search'), array('q' => '.+')); + $m->connect('search/'.$s.'?q=:q', + array('action' => $s.'search'), + array('q' => '.+')); } + // The second of these is needed to make the link work correctly + // when inserted into the page. The first is needed to match the + // route on the way in. Seems to be another Net_URL_Mapper bug to me. $m->connect('search/notice/rss', array('action' => 'noticesearchrss')); + $m->connect('search/notice/rss?q=:q', array('action' => 'noticesearchrss'), + array('q' => '.+')); // notice @@ -259,8 +266,8 @@ class Router foreach (array('xml', 'json', 'rss', 'atom') as $e) { $m->connect('api/direct_messages/sent.'.$e, array('action' => 'api', - 'apiaction' => 'direct_messages', - 'method' => 'sent.'.$e)); + 'apiaction' => 'direct_messages', + 'method' => 'sent.'.$e)); } $m->connect('api/direct_messages/destroy/:argument', @@ -324,9 +331,9 @@ class Router foreach (array('xml', 'json', 'rss', 'atom') as $e) { $m->connect('api/favorites.'.$e, - array('action' => 'api', - 'apiaction' => 'favorites', - 'method' => 'favorites.'.$e)); + array('action' => 'api', + 'apiaction' => 'favorites', + 'method' => 'favorites.'.$e)); } // notifications @@ -411,7 +418,7 @@ class Router $match = $this->m->match($path); } catch (Net_URL_Mapper_InvalidException $e) { common_log(LOG_ERR, "Problem getting route for $path - " . - $e->getMessage()); + $e->getMessage()); $cac = new ClientErrorAction("Page not found.", 404); $cac->showPage(); } @@ -429,6 +436,17 @@ class Router $args = $action_arg; } - return $this->m->generate($args, $params, $fragment); + $url = $this->m->generate($args, $params, $fragment); + + // Due to a bug in the Net_URL_Mapper code, the returned URL may + // contain a malformed query of the form ?p1=v1?p2=v2?p3=v3. We + // repair that here rather than modifying the upstream code... + + $qpos = strpos($url, '?'); + if ($qpos !== false) { + $url = substr($url, 0, $qpos+1) . + str_replace('?', '&', substr($url, $qpos+1)); + } + return $url; } } diff --git a/lib/rssaction.php b/lib/rssaction.php index 66c2d9e8cd..ddba862dcf 100644 --- a/lib/rssaction.php +++ b/lib/rssaction.php @@ -94,11 +94,11 @@ class Rss10Action extends Action function handle($args) { - // Get the list of notices - $this->notices = $this->getNotices(); // Parent handling, including cache check parent::handle($args); - $this->showRss($this->limit); + // Get the list of notices + $this->notices = $this->getNotices($this->limit); + $this->showRss(); } /** @@ -132,15 +132,13 @@ class Rss10Action extends Action return null; } - function showRss($limit=0) + function showRss() { - $notices = $this->getNotices($limit); - $this->initRss(); - $this->showChannel($notices); + $this->showChannel(); $this->showImage(); - foreach ($notices as $n) { + foreach ($this->notices as $n) { $this->showItem($n); } @@ -148,7 +146,7 @@ class Rss10Action extends Action $this->endRss(); } - function showChannel($notices) + function showChannel() { $channel = $this->getChannel(); @@ -167,7 +165,7 @@ class Rss10Action extends Action $this->elementStart('items'); $this->elementStart('rdf:Seq'); - foreach ($notices as $notice) { + foreach ($this->notices as $notice) { $this->element('sioct:MicroblogPost', array('rdf:resource' => $notice->uri)); } diff --git a/lib/search_engines.php b/lib/search_engines.php index 559107910c..7b9dbb6182 100644 --- a/lib/search_engines.php +++ b/lib/search_engines.php @@ -74,7 +74,7 @@ class SphinxSearch extends SearchEngine { //FIXME without LARGEST_POSSIBLE, the most recent results aren't returned // this probably has a large impact on performance - $LARGEST_POSSIBLE = 1e6; + $LARGEST_POSSIBLE = 1e6; if ($rss) { $this->sphinx->setLimits($offset, $count, $count, $LARGEST_POSSIBLE); @@ -109,12 +109,25 @@ class MySQLSearch extends SearchEngine { function query($q) { - if ('identica_people' === $this->table) - return $this->target->whereAdd('MATCH(nickname, fullname, location, bio, homepage) ' . - 'against (\''.addslashes($q).'\')'); - if ('identica_notices' === $this->table) - return $this->target->whereAdd('MATCH(content) ' . - 'against (\''.addslashes($q).'\')'); + if ('identica_people' === $this->table) { + $this->target->whereAdd('MATCH(nickname, fullname, location, bio, homepage) ' . + 'AGAINST (\''.addslashes($q).'\' IN BOOLEAN MODE)'); + if (strtolower($q) != $q) { + $this->target->whereAdd('MATCH(nickname, fullname, location, bio, homepage) ' . + 'AGAINST (\''.addslashes(strtolower($q)).'\' IN BOOLEAN MODE)', 'OR'); + } + return true; + } else if ('identica_notices' === $this->table) { + $this->target->whereAdd('MATCH(content) ' . + 'AGAINST (\''.addslashes($q).'\' IN BOOLEAN MODE)'); + if (strtolower($q) != $q) { + $this->target->whereAdd('MATCH(content) ' . + 'AGAINST (\''.addslashes(strtolower($q)).'\' IN BOOLEAN MODE)', 'OR'); + } + return true; + } else { + throw new ServerException('Unknown table: ' . $this->table); + } } } @@ -122,10 +135,13 @@ class PGSearch extends SearchEngine { function query($q) { - if ('identica_people' === $this->table) + if ('identica_people' === $this->table) { return $this->target->whereAdd('textsearch @@ plainto_tsquery(\''.addslashes($q).'\')'); - if ('identica_notices' === $this->table) + } else if ('identica_notices' === $this->table) { return $this->target->whereAdd('to_tsvector(\'english\', content) @@ plainto_tsquery(\''.addslashes($q).'\')'); + } else { + throw new ServerException('Unknown table: ' . $this->table); + } } } diff --git a/lib/twitterapi.php b/lib/twitterapi.php index e7239acd5e..b8357c6889 100644 --- a/lib/twitterapi.php +++ b/lib/twitterapi.php @@ -238,21 +238,6 @@ class TwitterapiAction extends Action $this->elementEnd('item'); } - function show_twitter_atom_entry($entry) - { - $this->elementStart('entry'); - $this->element('title', null, $entry['title']); - $this->element('content', array('type' => 'html'), $entry['content']); - $this->element('id', null, $entry['id']); - $this->element('published', null, $entry['published']); - $this->element('updated', null, $entry['updated']); - $this->element('link', array('href' => $entry['link'], 'rel' => 'alternate', 'type' => 'text/html'), null); - $this->elementStart('author'); - $this->element('name', null, $entry['author']); - $this->elementEnd('author'); - $this->elementEnd('entry'); - } - function show_json_objects($objects) { print(json_encode($objects)); @@ -383,7 +368,7 @@ class TwitterapiAction extends Action } if (!is_null($selfuri)) { - $this->element('link', array('href' => $selfuri, + $this->element('link', array('href' => $selfuri, 'rel' => 'self', 'type' => 'application/atom+xml'), null); } @@ -392,13 +377,11 @@ class TwitterapiAction extends Action if (is_array($notice)) { foreach ($notice as $n) { - $entry = $this->twitter_rss_entry_array($n); - $this->show_twitter_atom_entry($entry); + $this->raw($n->asAtomEntry()); } } else { while ($notice->fetch()) { - $entry = $this->twitter_rss_entry_array($notice); - $this->show_twitter_atom_entry($entry); + $this->raw($notice->asAtomEntry()); } } @@ -578,13 +561,16 @@ class TwitterapiAction extends Action function init_twitter_atom() { $this->startXML(); - $this->elementStart('feed', array('xmlns' => 'http://www.w3.org/2005/Atom', 'xml:lang' => 'en-US')); + // FIXME: don't hardcode the language here! + $this->elementStart('feed', array('xmlns' => 'http://www.w3.org/2005/Atom', + 'xml:lang' => 'en-US', + 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0')); } function end_twitter_atom() { - $this->endXML(); $this->elementEnd('feed'); + $this->endXML(); } function show_profile($profile, $content_type='xml', $notice=null) diff --git a/scripts/pingqueuehandler.php b/scripts/pingqueuehandler.php index 55a266e4a4..ada6ecdba2 100644 --- a/scripts/pingqueuehandler.php +++ b/scripts/pingqueuehandler.php @@ -34,7 +34,7 @@ require_once(INSTALLDIR . '/lib/queuehandler.php'); set_error_handler('common_error_handler'); class PingQueueHandler extends QueueHandler { - + function transport() { return 'ping'; } @@ -47,7 +47,7 @@ class PingQueueHandler extends QueueHandler { function handle_notice($notice) { return ping_broadcast_notice($notice); } - + function finish() { } } diff --git a/theme/base/css/display.css b/theme/base/css/display.css index c741ed4cba..90cd00d553 100644 --- a/theme/base/css/display.css +++ b/theme/base/css/display.css @@ -150,7 +150,9 @@ font-weight:bold; #form_openid_login legend, #form_search legend, #form_invite legend, -#form_notice_delete legend { +#form_notice_delete legend, +#form_password_recover legend, +#form_password_change legend { display:none; } @@ -419,6 +421,7 @@ padding:0; display:none; } #form_notice textarea { +float:left; border-radius:7px; -moz-border-radius:7px; -webkit-border-radius:7px; @@ -429,30 +432,19 @@ padding:7px 7px 16px 7px; } #form_notice label { display:block; +float:left; font-size:1.3em; margin-bottom:7px; } -#form_notice .form_data li { -float:left; -} - -#form_notice #notice_attach_file label, #form_notice #notice_submit label { display:none; } - -#form_notice #notice_attachment { -margin-top:25px; -margin-left:4px; -} - #form_notice .form_note { position:absolute; top:99px; right:98px; z-index:9; } - #form_notice .form_note dt { font-weight:bold; display:none; @@ -462,42 +454,19 @@ font-weight:bold; line-height:1.15; padding:1px 2px; } - -#form_notice #notice_data-attach_view { -position:absolute; -top:25px; -right:30px; -margin-left:4px; -padding:0; -width:16px; -height:16px; -border:0; -text-indent:-9999px; -} -#form_notice .form_actions { +#form_notice #notice_action-submit { +width:60px; +padding:8px; position:absolute; bottom:0; right:0; } -#form_notice .form_actions input.submit { -width:60px; -padding:8px; -} - -#form_notice li { -margin-bottom:0; -} - -#form_notice #notice_to { -margin-bottom:7px; -} - -#notice_to label { -float:left; -margin-right:18px; +#form_notice label[for=to] { margin-top:11px; } -#notice_to select { +#form_notice select[id=to] { +margin-bottom:7px; +margin-left:18px; float:left; } /*end FORM NOTICE*/ diff --git a/theme/base/css/ie6.css b/theme/base/css/ie6.css index 10b31cbcb5..fa6ec92d2f 100644 --- a/theme/base/css/ie6.css +++ b/theme/base/css/ie6.css @@ -9,3 +9,6 @@ margin-left:0; .entity_profile .entity_depiction { margin-bottom:123px; } +.notice div.entry-content { +width:63%; +} diff --git a/theme/base/images/icons/icon_processing.gif b/theme/base/images/icons/icon_processing.gif new file mode 100644 index 0000000000..d0bce15423 Binary files /dev/null and b/theme/base/images/icons/icon_processing.gif differ diff --git a/theme/default/css/display.css b/theme/default/css/display.css index 85b5aa13e5..bb0b84a67a 100644 --- a/theme/default/css/display.css +++ b/theme/default/css/display.css @@ -94,6 +94,11 @@ color:#333; #form_notice.warning #notice_text-count { color:#000; } +#form_notice.processing #notice_action-submit { +background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%; +cursor:wait; +text-indent:-9999px; +} #nav_register a { diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css index 576a2e14be..69be116233 100644 --- a/theme/identica/css/display.css +++ b/theme/identica/css/display.css @@ -94,7 +94,11 @@ color:#333; #form_notice.warning #notice_text-count { color:#000; } - +#form_notice.processing #notice_action-submit { +background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%; +cursor:wait; +text-indent:-9999px; +} #nav_register a { text-decoration:none;