X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=lib%2Futil.php;h=11967709106c9481200ff733142df5c02a181051;hb=a1da43417e319b7cd49199667794163ad8e3d8ed;hp=1bc5b95b00ca452581a4c2ffb3f3753134efe804;hpb=22057e01bd6fdf366340e6fdbdf6bb1252bceb8c;p=quix0rs-gnu-social.git diff --git a/lib/util.php b/lib/util.php index 1bc5b95b00..1196770910 100644 --- a/lib/util.php +++ b/lib/util.php @@ -114,11 +114,11 @@ function common_element($tag, $attrs=NULL, $content=NULL) { common_element_end($tag); } -function common_start_xml($doc=NULL, $public=NULL, $system=NULL) { +function common_start_xml($doc=NULL, $public=NULL, $system=NULL, $indent=true) { global $xw; $xw = new XMLWriter(); $xw->openURI('php://output'); - $xw->setIndent(true); + $xw->setIndent($indent); $xw->startDocument('1.0', 'UTF-8'); if ($doc) { $xw->writeDTD($doc, $public, $system); @@ -146,7 +146,9 @@ function common_init_language() { bind_textdomain_codeset("laconica", "UTF-8"); textdomain("laconica"); setlocale(LC_CTYPE, 'C'); - common_log(LOG_INFO,'Language requested:'.$language.' Locale set:'.$locale_set,__FILE__); + if(!$locale_set) { + common_log(LOG_INFO,'Language requested:'.$language.' - locale could not be set:',__FILE__); + } } define('PAGE_TYPE_PREFS', 'text/html,application/xhtml+xml,application/xml;q=0.3,text/xml;q=0.2'); @@ -178,6 +180,9 @@ function common_show_header($pagetitle, $callable=NULL, $data=NULL, $headercall= common_element('script', array('type' => 'text/javascript', 'src' => common_path('js/jquery.form.js')), ' '); + common_element('script', array('type' => 'text/javascript', + 'src' => common_path('js/xbImportNode.js')), + ' '); common_element('script', array('type' => 'text/javascript', 'src' => common_path('js/util.js?version='.LACONICA_VERSION)), ' '); @@ -230,7 +235,7 @@ function common_show_header($pagetitle, $callable=NULL, $data=NULL, $headercall= common_element_start('div', array('id' => 'content')); } -function common_start_html($type=NULL) { +function common_start_html($type=NULL, $indent=true) { if (!$type) { $httpaccept = isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : NULL; @@ -250,7 +255,7 @@ function common_start_html($type=NULL) { common_start_xml('html', '-//W3C//DTD XHTML 1.0 Strict//EN', - 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'); + 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd', $indent); # FIXME: correct language for interface @@ -312,7 +317,6 @@ function common_nav_menu() { _('Home')); } common_menu_item(common_local_url('peoplesearch'), _('Search')); - common_menu_item(common_local_url('tags'), _('Tags')); if ($user) { common_menu_item(common_local_url('profilesettings'), _('Settings')); @@ -327,6 +331,8 @@ function common_nav_menu() { } common_menu_item(common_local_url('openidlogin'), _('OpenID')); } + common_menu_item(common_local_url('doc', array('title' => 'help')), + _('Help')); common_element_end('ul'); } @@ -704,6 +710,7 @@ function common_render_content($text, $notice) { $id = $notice->profile_id; $r = preg_replace('/(^|\s+)@([A-Za-z0-9]{1,64})/e', "'\\1@'.common_at_link($id, '\\2')", $r); $r = preg_replace('/^T ([A-Z0-9]{1,64}) /e', "'T '.common_at_link($id, '\\1').' '", $r); + $r = preg_replace('/(^|\s+)@#([A-Za-z0-9]{1,64})/e', "'\\1@#'.common_at_hash_link($id, '\\2')", $r); return $r; } @@ -711,12 +718,125 @@ function common_render_text($text) { $r = htmlspecialchars($text); $r = preg_replace('/[\x{0}-\x{8}\x{b}-\x{c}\x{e}-\x{19}]/', '', $r); - $r = preg_replace('@https?://[^)\]>\s]+@', '\0', $r); + $r = preg_replace_callback('@https?://[^\]>\s]+@', 'common_render_uri_thingy', $r); $r = preg_replace('/(^|\s+)#([A-Za-z0-9_\-\.]{1,64})/e', "'\\1#'.common_tag_link('\\2')", $r); # XXX: machine tags return $r; } +function common_render_uri_thingy($matches) { + $uri = $matches[0]; + $trailer = ''; + + # Some heuristics for extracting URIs from surrounding punctuation + # Strip from trailing text... + if (preg_match('/^(.*)([,.:"\']+)$/', $uri, $matches)) { + $uri = $matches[1]; + $trailer = $matches[2]; + } + + $pairs = array( + ']' => '[', # technically disallowed in URIs, but used in Java docs + ')' => '(', # far too frequent in Wikipedia and MSDN + ); + $final = substr($uri, -1, 1); + if (isset($pairs[$final])) { + $openers = substr_count($uri, $pairs[$final]); + $closers = substr_count($uri, $final); + if ($closers > $openers) { + // Assume the paren was opened outside the URI + $uri = substr($uri, 0, -1); + $trailer = $final . $trailer; + } + } + if ($longurl = common_longurl($uri)) { + $longurl = htmlentities($longurl, ENT_QUOTES, 'UTF-8'); + $title = " title='$longurl'"; + } + else $title = ''; + + return '' . $uri . '' . $trailer; +} + +function common_longurl($uri) { + $uri_e = urlencode($uri); + $longurl = unserialize(file_get_contents("http://api.longurl.org/v1/expand?format=php&url=$uri_e")); + if (empty($longurl['long_url']) || $uri === $longurl['long_url']) return false; + return stripslashes($longurl['long_url']); +} + +function common_shorten_links($text) { + // \s = not a horizontal whitespace character (since PHP 5.2.4) + // RYM this should prevent * preceded URLs from being processed but it its a char +// $r = preg_replace('@[^*](https?://[^)\]>\s]+)@e', "common_shorten_link('\\1')", $r); + return preg_replace('@https?://[^)\]>\s]+@e', "common_shorten_link('\\0')", $text); +} + +function common_shorten_link($long_url) { + + $user = common_current_user(); + + $curlh = curl_init(); + curl_setopt($curlh, CURLOPT_CONNECTTIMEOUT, 20); // # seconds to wait + curl_setopt($curlh, CURLOPT_USERAGENT, 'Laconica'); + curl_setopt($curlh, CURLOPT_RETURNTRANSFER, true); + + switch($user->urlshorteningservice) { + case 'ur1.ca': + $short_url_service = new LilUrl; + $short_url = $short_url_service->shorten($long_url); + break; + + case '2tu.us': + $short_url_service = new TightUrl; + $short_url = $short_url_service->shorten($long_url); + break; + + case 'ptiturl.com': + $short_url_service = new PtitUrl; + $short_url = $short_url_service->shorten($long_url); + break; + + case 'bit.ly': + curl_setopt($curlh, CURLOPT_URL, 'http://bit.ly/api?method=shorten&long_url='.urlencode($long_url)); + $short_url = current(json_decode(curl_exec($curlh))->results)->hashUrl; + break; + + case 'is.gd': + curl_setopt($curlh, CURLOPT_URL, 'http://is.gd/api.php?longurl='.urlencode($long_url)); + $short_url = curl_exec($curlh); + break; + case 'snipr.com': + curl_setopt($curlh, CURLOPT_URL, 'http://snipr.com/site/snip?r=simple&link='.urlencode($long_url)); + $short_url = curl_exec($curlh); + break; + case 'metamark.net': + curl_setopt($curlh, CURLOPT_URL, 'http://metamark.net/api/rest/simple?long_url='.urlencode($long_url)); + $short_url = curl_exec($curlh); + break; + case 'tinyurl.com': + curl_setopt($curlh, CURLOPT_URL, 'http://tinyurl.com/api-create.php?url='.urlencode($long_url)); + $short_url = curl_exec($curlh); + break; + default: + $short_url = false; + } + + curl_close($curlh); + + if ($short_url) { + return $short_url; + } + return $long_url; +} + +function common_xml_safe_str($str) { + $xmlStr = htmlentities(iconv('UTF-8', 'UTF-8//IGNORE', $str), ENT_NOQUOTES, 'UTF-8'); + + // Replace control, formatting, and surrogate characters with '*', ala Twitter + return preg_replace('/[\p{Cc}\p{Cf}\p{Cs}]/u', '*', $str); +} + function common_tag_link($tag) { $canonical = common_canonical_tag($tag); $url = common_local_url('tag', array('tag' => $canonical)); @@ -727,6 +847,10 @@ function common_canonical_tag($tag) { return strtolower(str_replace(array('-', '_', '.'), '', $tag)); } +function common_valid_profile_tag($str) { + return preg_match('/^[A-Za-z0-9_\-\.]{1,64}$/', $str); +} + function common_at_link($sender_id, $nickname) { $sender = Profile::staticGet($sender_id); $recipient = common_relative_profile($sender, common_canonical_nickname($nickname)); @@ -737,6 +861,22 @@ function common_at_link($sender_id, $nickname) { } } +function common_at_hash_link($sender_id, $tag) { + $user = User::staticGet($sender_id); + if (!$user) { + return $tag; + } + $tagged = Profile_tag::getTagged($user->id, common_canonical_tag($tag)); + if ($tagged) { + $url = common_local_url('subscriptions', + array('nickname' => $user->nickname, + 'tag' => $tag)); + return ''.$tag.''; + } else { + return $tag; + } +} + function common_relative_profile($sender, $nickname, $dt=NULL) { # Try to find profiles this profile is subscribed to that have this nickname $recipient = new Profile(); @@ -830,10 +970,26 @@ function common_fancy_url($action, $args=NULL) { } else { return common_path(''); } + case 'featured': + if ($args && isset($args['page'])) { + return common_path('featured?page=' . $args['page']); + } else { + return common_path('featured'); + } + case 'favorited': + if ($args && isset($args['page'])) { + return common_path('favorited?page=' . $args['page']); + } else { + return common_path('favorited'); + } case 'publicrss': return common_path('rss'); case 'publicxrds': return common_path('xrds'); + case 'featuredrss': + return common_path('featuredrss'); + case 'favoritedrss': + return common_path('favoritedrss'); case 'opensearch': if ($args && $args['type']) { return common_path('opensearch/'.$args['type']); @@ -848,6 +1004,8 @@ function common_fancy_url($action, $args=NULL) { case 'unsubscribe': case 'invite': return common_path('main/'.$action); + case 'tagother': + return common_path('main/tagother?id='.$args['id']); case 'register': if ($args && $args['code']) { return common_path('main/register/'.$args['code']); @@ -860,6 +1018,8 @@ function common_fancy_url($action, $args=NULL) { } else { return common_path('main/remote'); } + case 'nudge': + return common_path($args['nickname'].'/nudge'); case 'openidlogin': return common_path('main/openid'); case 'profilesettings': @@ -872,6 +1032,8 @@ function common_fancy_url($action, $args=NULL) { return common_path('settings/sms'); case 'twittersettings': return common_path('settings/twitter'); + case 'othersettings': + return common_path('settings/other'); case 'newnotice': if ($args && $args['replyto']) { return common_path('notice/new?replyto='.$args['replyto']); @@ -886,11 +1048,10 @@ function common_fancy_url($action, $args=NULL) { } else { return common_path('notice/delete'); } + case 'microsummary': case 'xrds': case 'foaf': return common_path($args['nickname'].'/'.$action); - case 'subscriptions': - case 'subscribers': case 'all': case 'replies': case 'inbox': @@ -900,6 +1061,20 @@ function common_fancy_url($action, $args=NULL) { } else { return common_path($args['nickname'].'/'.$action); } + case 'subscriptions': + case 'subscribers': + $nickname = $args['nickname']; + unset($args['nickname']); + if (isset($args['tag'])) { + $tag = $args['tag']; + unset($args['tag']); + } + $params = http_build_query($args); + if ($params) { + return common_path($nickname.'/'.$action . (($tag) ? '/' . $tag : '') . '?' . $params); + } else { + return common_path($nickname.'/'.$action . (($tag) ? '/' . $tag : '')); + } case 'allrss': return common_path($args['nickname'].'/all/rss'); case 'repliesrss': @@ -912,6 +1087,9 @@ function common_fancy_url($action, $args=NULL) { } else { return common_path($args['nickname']); } + + case 'usertimeline': + return common_path("api/statuses/user_timeline/".$args['nickname'].".atom"); case 'confirmaddress': return common_path('main/confirmaddress/'.$args['code']); case 'userbyid': @@ -940,6 +1118,10 @@ function common_fancy_url($action, $args=NULL) { $path = 'tags'; } return common_path($path . (($args) ? ('?' . http_build_query($args)) : '')); + case 'peopletag': + $path = 'peopletag/' . $args['tag']; + unset($args['tag']); + return common_path($path . (($args) ? ('?' . http_build_query($args)) : '')); case 'tags': return common_path('tags' . (($args) ? ('?' . http_build_query($args)) : '')); case 'favor': @@ -965,18 +1147,22 @@ function common_fancy_url($action, $args=NULL) { switch (strtolower($args['method'])) { case 'user_timeline.rss': return common_path('api/statuses/user_timeline/'.$args['argument'].'.rss'); - case 'user_timeline.atom': + case 'user_timeline.atom': return common_path('api/statuses/user_timeline/'.$args['argument'].'.rss'); case 'user_timeline.rss': return common_path('api/statuses/user_timeline/'.$args['argument'].'.rss'); - case 'user_timeline.atom': + case 'user_timeline.atom': return common_path('api/statuses/user_timeline/'.$args['argument'].'.rss'); default: return common_simple_url($action, $args); } default: return common_simple_url($action, $args); } case 'sup': - return common_path('main/sup'); + if ($args && isset($args['seconds'])) { + return common_path('main/sup?seconds='.$args['seconds']); + } else { + return common_path('main/sup'); + } default: return common_simple_url($action, $args); } @@ -1098,14 +1284,21 @@ function common_save_replies($notice) { } # extract all @messages $cnt = preg_match_all('/(?:^|\s)@([a-z0-9]{1,64})/', $notice->content, $match); - if (!$cnt && !$tname) { - return true; + + $names = array(); + + if ($cnt || $tname) { + # XXX: is there another way to make an array copy? + $names = ($tname) ? array_unique(array_merge(array(strtolower($tname)), $match[1])) : array_unique($match[1]); } - # XXX: is there another way to make an array copy? - $names = ($tname) ? array_unique(array_merge(array(strtolower($tname)), $match[1])) : array_unique($match[1]); + $sender = Profile::staticGet($notice->profile_id); + + $replied = array(); + # store replied only for first @ (what user/notice what the reply directed, # we assume first @ is it) + for ($i=0; $icreated); @@ -1130,6 +1323,28 @@ function common_save_replies($notice) { common_log(LOG_ERR, 'DB error inserting reply: ' . $last_error->message); common_server_error(sprintf(_('DB error inserting reply: %s'), $last_error->message)); return; + } else { + $replied[$recipient->id] = 1; + } + } + + # Hash format replies, too + $cnt = preg_match_all('/(?:^|\s)@#([a-z0-9]{1,64})/', $notice->content, $match); + if ($cnt) { + foreach ($match[1] as $tag) { + $tagged = Profile_tag::getTagged($sender->id, $tag); + foreach ($tagged as $t) { + if (!$replied[$t->id]) { + $reply = new Reply(); + $reply->notice_id = $notice->id; + $reply->profile_id = $t->id; + $id = $reply->insert(); + if (!$id) { + common_log_db_error($reply, 'INSERT', __FILE__); + return; + } + } + } } } } @@ -1137,12 +1352,12 @@ function common_save_replies($notice) { function common_broadcast_notice($notice, $remote=false) { // Check to see if notice should go to Twitter - $flink = Foreign_link::getForeignLink($notice->profile_id, 1); // 1 == Twitter + $flink = Foreign_link::getByUserID($notice->profile_id, 1); // 1 == Twitter if (($flink->noticesync & FOREIGN_NOTICE_SEND) == FOREIGN_NOTICE_SEND) { // If it's not a Twitter-style reply, or if the user WANTS to send replies... - if (!preg_match('/^@[a-zA-Z0-9_]{1,15}\b/', $notice->content) || + if (!preg_match('/^@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) || (($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) == FOREIGN_NOTICE_SEND_REPLY)) { $result = common_twitter_broadcast($notice, $flink); @@ -1312,12 +1527,13 @@ function common_notice_form($action=NULL, $content=NULL) { common_element('label', array('for' => 'status_textarea', 'id' => 'status_label'), sprintf(_('What\'s up, %s?'), $user->nickname)); - common_element('span', array('id' => 'counter', 'class' => 'counter'), '140'); + common_element('span', array('id' => 'counter', 'class' => 'counter'), '140'); common_element('textarea', array('id' => 'status_textarea', 'cols' => 60, 'rows' => 3, 'name' => 'status_textarea'), ($content) ? $content : ''); + common_hidden('token', common_session_token()); if ($action) { common_hidden('returnto', $action); } @@ -1684,13 +1900,25 @@ function common_disfavor_form($notice) { 'method' => 'post', 'class' => 'disfavor', 'action' => common_local_url('disfavor'))); - common_hidden('token', common_session_token()); - common_hidden('notice', $notice->id); + + common_element('input', array('type' => 'hidden', + 'name' => 'token-'. $notice->id, + 'id' => 'token-'. $notice->id, + 'class' => 'token', + 'value' => common_session_token())); + + common_element('input', array('type' => 'hidden', + 'name' => 'notice', + 'id' => 'notice-n'. $notice->id, + 'class' => 'notice', + 'value' => $notice->id)); + common_element('input', array('type' => 'submit', 'id' => 'disfavor-submit-' . $notice->id, 'name' => 'disfavor-submit-' . $notice->id, 'class' => 'disfavor', - 'value' => '♥')); + 'value' => 'Disfavor favorite', + 'title' => 'Remove this message from favorites')); common_element_end('form'); } @@ -1699,16 +1927,91 @@ function common_favor_form($notice) { 'method' => 'post', 'class' => 'favor', 'action' => common_local_url('favor'))); - common_hidden('token', common_session_token()); - common_hidden('notice', $notice->id); + + common_element('input', array('type' => 'hidden', + 'name' => 'token-'. $notice->id, + 'id' => 'token-'. $notice->id, + 'class' => 'token', + 'value' => common_session_token())); + + common_element('input', array('type' => 'hidden', + 'name' => 'notice', + 'id' => 'notice-n'. $notice->id, + 'class' => 'notice', + 'value' => $notice->id)); + common_element('input', array('type' => 'submit', 'id' => 'favor-submit-' . $notice->id, 'name' => 'favor-submit-' . $notice->id, 'class' => 'favor', - 'value' => '♡')); + 'value' => 'Add to favorites', + 'title' => 'Add this message to favorites')); + common_element_end('form'); +} + +function common_nudge_form($profile) { + common_element_start('form', array('id' => 'nudge', 'method' => 'post', + 'action' => common_local_url('nudge', array('nickname' => $profile->nickname)))); + common_hidden('token', common_session_token()); + common_element('input', array('type' => 'submit', + 'class' => 'submit', + 'value' => _('Send a nudge'))); + common_element_end('form'); +} +function common_nudge_response() { + common_element('p', array('id' => 'nudge_response'), _('Nudge sent!')); +} + +function common_subscribe_form($profile) { + common_element_start('form', array('id' => 'subscribe-' . $profile->nickname, + 'method' => 'post', + 'class' => 'subscribe', + 'action' => common_local_url('subscribe'))); + common_hidden('token', common_session_token()); + common_element('input', array('id' => 'subscribeto-' . $profile->nickname, + 'name' => 'subscribeto', + 'type' => 'hidden', + 'value' => $profile->nickname)); + common_element('input', array('type' => 'submit', + 'class' => 'submit', + 'value' => _('Subscribe'))); common_element_end('form'); } +function common_unsubscribe_form($profile) { + common_element_start('form', array('id' => 'unsubscribe-' . $profile->nickname, + 'method' => 'post', + 'class' => 'unsubscribe', + 'action' => common_local_url('unsubscribe'))); + common_hidden('token', common_session_token()); + common_element('input', array('id' => 'unsubscribeto-' . $profile->nickname, + 'name' => 'unsubscribeto', + 'type' => 'hidden', + 'value' => $profile->nickname)); + common_element('input', array('type' => 'submit', + 'class' => 'submit', + 'value' => _('Unsubscribe'))); + common_element_end('form'); +} + +// XXX: Refactor this code +function common_profile_new_message_nudge ($cur, $profile) { + $user = User::staticGet('id', $profile->id); + + if ($cur && $cur->id != $user->id && $cur->mutuallySubscribed($user)) { + common_element_start('li', array('id' => 'profile_send_a_new_message')); + common_element('a', array('href' => common_local_url('newmessage', array('to' => $user->id))), + _('Send a message')); + common_element_end('li'); + + if ($user->email && $user->emailnotifynudge) { + common_element_start('li', array('id' => 'profile_nudge')); + common_nudge_form($user); + common_element_end('li'); + } + } +} + function common_cache_key($extra) { return 'laconica:' . common_keyize(common_config('site', 'name')) . ':' . $extra; }