]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - lib/util.php
Give users more control over URL shortening
[quix0rs-gnu-social.git] / lib / util.php
index c7cb4f313ea459c270918046106bfa53f1a71450..c78ed33bd52f1e55efffa16eef9facfc3f83e85a 100644 (file)
@@ -52,17 +52,43 @@ function common_init_language()
 {
     mb_internal_encoding('UTF-8');
 
-    // gettext seems very picky... We first need to setlocale()
-    // to a locale which _does_ exist on the system, and _then_
-    // we can set in another locale that may not be set up
-    // (say, ga_ES for Galego/Galician) it seems to take it.
-    common_init_locale("en_US");
-
     // Note that this setlocale() call may "fail" but this is harmless;
     // gettext will still select the right language.
     $language = common_language();
     $locale_set = common_init_locale($language);
 
+    if (!$locale_set) {
+        // The requested locale doesn't exist on the system.
+        //
+        // gettext seems very picky... We first need to setlocale()
+        // to a locale which _does_ exist on the system, and _then_
+        // we can set in another locale that may not be set up
+        // (say, ga_ES for Galego/Galician) it seems to take it.
+        //
+        // For some reason C and POSIX which are guaranteed to work
+        // don't do the job. en_US.UTF-8 should be there most of the
+        // time, but not guaranteed.
+        $ok = common_init_locale("en_US");
+        if (!$ok) {
+            // Try to find a complete, working locale...
+            // @fixme shelling out feels awfully inefficient
+            // but I don't think there's a more standard way.
+            $all = `locale -a`;
+            foreach (explode("\n", $all) as $locale) {
+                if (preg_match('/\.utf[-_]?8$/i', $locale)) {
+                    $ok = setlocale(LC_ALL, $locale);
+                    if ($ok) {
+                        break;
+                    }
+                }
+            }
+            if (!$ok) {
+                common_log(LOG_ERR, "Unable to find a UTF-8 locale on this system; UI translations may not work.");
+            }
+        }
+        $locale_set = common_init_locale($language);
+    }
+
     setlocale(LC_CTYPE, 'C');
     // So we do not have to make people install the gettext locales
     $path = common_config('site','locale_path');
@@ -105,11 +131,13 @@ function common_language()
 
     // Otherwise, find the best match for the languages requested by the
     // user's browser...
-    $httplang = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : null;
-    if (!empty($httplang)) {
-        $language = client_prefered_language($httplang);
-        if ($language)
-          return $language;
+    if (common_config('site', 'langdetect')) {
+        $httplang = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : null;
+        if (!empty($httplang)) {
+            $language = client_prefered_language($httplang);
+            if ($language)
+              return $language;
+        }
     }
 
     // Finally, if none of the above worked, use the site's default...
@@ -131,6 +159,11 @@ function common_munge_password($password, $id)
 
 function common_check_user($nickname, $password)
 {
+    // empty nickname always unacceptable
+    if (empty($nickname)) {
+        return false;
+    }
+
     $authenticatedUser = false;
 
     if (Event::handle('StartCheckPassword', array($nickname, $password, &$authenticatedUser))) {
@@ -550,7 +583,7 @@ function common_find_mentions($text, $notice)
             } else if (!empty($originalMentions) &&
                        array_key_exists($nickname, $originalMentions)) {
 
-                $mention = $originalMentions[$nickname];
+                $mentioned = $originalMentions[$nickname];
             } else {
                 $mentioned = common_relative_profile($sender, $nickname);
             }
@@ -770,7 +803,7 @@ function common_linkify($url) {
     }
 
     if (!empty($f)) {
-        if ($f->getEnclosure()) {
+        if ($f->getEnclosure() || File_oembed::staticGet('file_id',$f->id)) {
             $is_attachment = true;
             $attachment_id = $f->id;
 
@@ -795,15 +828,47 @@ function common_linkify($url) {
 
 function common_shorten_links($text)
 {
-    $maxLength = Notice::maxContent();
-    if ($maxLength == 0 || mb_strlen($text) <= $maxLength) return $text;
-    return common_replace_urls_callback($text, array('File_redirection', 'makeShort'));
+    common_debug("common_shorten_links() called");
+
+    $user = common_current_user();
+
+    $maxLength = User_urlshortener_prefs::maxNoticeLength($user);
+
+    common_debug("maxLength = $maxLength");
+
+    if (mb_strlen($text) > $maxLength) {
+        common_debug("Forcing shortening");
+        return common_replace_urls_callback($text, array('File_redirection', 'forceShort'));
+    } else {
+        common_debug("Not forcing shortening");
+        return common_replace_urls_callback($text, array('File_redirection', 'makeShort'));
+    }
 }
 
 function common_xml_safe_str($str)
 {
-    // Neutralize control codes and surrogates
-       return preg_replace('/[\p{Cc}\p{Cs}]/u', '*', $str);
+    // Replace common eol and extra whitespace input chars
+    $unWelcome = array(
+        "\t",  // tab
+        "\n",  // newline
+        "\r",  // cr
+        "\0",  // null byte eos
+        "\x0B" // vertical tab
+    );
+
+    $replacement = array(
+        ' ', // single space
+        ' ',
+        '',  // nothing
+        '',
+        ' '
+    );
+
+    $str = str_replace($unWelcome, $replacement, $str);
+
+    // Neutralize any additional control codes and UTF-16 surrogates
+    // (Twitter uses '*')
+    return preg_replace('/[\p{Cc}\p{Cs}]/u', '*', $str);
 }
 
 function common_tag_link($tag)
@@ -833,7 +898,7 @@ function common_valid_profile_tag($str)
 function common_group_link($sender_id, $nickname)
 {
     $sender = Profile::staticGet($sender_id);
-    $group = User_group::getForNickname($nickname);
+    $group = User_group::getForNickname($nickname, $sender);
     if ($sender && $group && $sender->isMember($group)) {
         $attrs = array('href' => $group->permalink(),
                        'class' => 'url');
@@ -1123,19 +1188,10 @@ function common_enqueue_notice($notice)
         $transports[] = 'plugin';
     }
 
-    $xmpp = common_config('xmpp', 'enabled');
-
-    if ($xmpp) {
-        $transports[] = 'jabber';
-    }
-
     // @fixme move these checks into QueueManager and/or individual handlers
     if ($notice->is_local == Notice::LOCAL_PUBLIC ||
         $notice->is_local == Notice::LOCAL_NONPUBLIC) {
         $transports = array_merge($transports, $localTransports);
-        if ($xmpp) {
-            $transports[] = 'public';
-        }
     }
 
     if (Event::handle('StartEnqueueNotice', array($notice, &$transports))) {
@@ -1344,6 +1400,55 @@ function common_valid_tag($tag)
     return false;
 }
 
+/**
+ * Determine if given domain or address literal is valid
+ * eg for use in JIDs and URLs. Does not check if the domain
+ * exists!
+ *
+ * @param string $domain
+ * @return boolean valid or not
+ */
+function common_valid_domain($domain)
+{
+    $octet = "(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])";
+    $ipv4 = "(?:$octet(?:\.$octet){3})";
+    if (preg_match("/^$ipv4$/u", $domain)) return true;
+
+    $group = "(?:[0-9a-f]{1,4})";
+    $ipv6 = "(?:\[($group(?::$group){0,7})?(::)?($group(?::$group){0,7})?\])"; // http://tools.ietf.org/html/rfc3513#section-2.2
+
+    if (preg_match("/^$ipv6$/ui", $domain, $matches)) {
+        $before = explode(":", $matches[1]);
+        $zeroes = $matches[2];
+        $after = explode(":", $matches[3]);
+        if ($zeroes) {
+            $min = 0;
+            $max = 7;
+        } else {
+            $min = 1;
+            $max = 8;
+        }
+        $explicit = count($before) + count($after);
+        if ($explicit < $min || $explicit > $max) {
+            return false;
+        }
+        return true;
+    }
+
+    try {
+        require_once "Net/IDNA.php";
+        $idn = Net_IDNA::getInstance();
+        $domain = $idn->encode($domain);
+    } catch (Exception $e) {
+        return false;
+    }
+
+    $subdomain = "(?:[a-z0-9][a-z0-9-]*)"; // @fixme
+    $fqdn = "(?:$subdomain(?:\.$subdomain)*\.?)";
+
+    return preg_match("/^$fqdn$/ui", $domain);
+}
+
 /* Following functions are copied from MediaWiki GlobalFunctions.php
  * and written by Evan Prodromou. */
 
@@ -1440,7 +1545,15 @@ function common_copy_args($from)
     $to = array();
     $strip = get_magic_quotes_gpc();
     foreach ($from as $k => $v) {
-        $to[$k] = ($strip) ? stripslashes($v) : $v;
+        if($strip) {
+            if(is_array($v)) {
+                $to[$k] = common_copy_args($v);
+            } else {
+                $to[$k] = stripslashes($v);
+            }
+        } else {
+            $to[$k] = $v;
+        }
     }
     return $to;
 }
@@ -1468,7 +1581,8 @@ function common_user_uri(&$user)
 function common_notice_uri(&$notice)
 {
     return common_local_url('shownotice',
-                            array('notice' => $notice->id));
+                            array('notice' => $notice->id),
+                            null, null, false);
 }
 
 // 36 alphanums - lookalikes (0, O, 1, I) = 32 chars = 5 bits
@@ -1632,30 +1746,42 @@ function common_database_tablename($tablename)
 /**
  * Shorten a URL with the current user's configured shortening service,
  * or ur1.ca if configured, or not at all if no shortening is set up.
- * Length is not considered.
  *
- * @param string $long_url
+ * @param string  $long_url original URL
+ * @param boolean $force    Force shortening (used when notice is too long)
+ *
  * @return string may return the original URL if shortening failed
  *
  * @fixme provide a way to specify a particular shortener
  * @fixme provide a way to specify to use a given user's shortening preferences
  */
-function common_shorten_url($long_url)
+
+function common_shorten_url($long_url, $force = false)
 {
+    common_debug("Shortening URL '$long_url' (force = $force)");
+
     $long_url = trim($long_url);
+
     $user = common_current_user();
-    if (empty($user)) {
-        // common current user does not find a user when called from the XMPP daemon
-        // therefore we'll set one here fix, so that XMPP given URLs may be shortened
-        $shortenerName = 'ur1.ca';
-    } else {
-        $shortenerName = $user->urlshorteningservice;
+
+    $maxUrlLength = User_urlshortener_prefs::maxUrlLength($user);
+    common_debug("maxUrlLength = $maxUrlLength");
+
+    // $force forces shortening even if it's not strictly needed
+
+    if (mb_strlen($long_url) < $maxUrlLength && !$force) {
+        common_debug("Skipped shortening URL.");
+        return $long_url;
     }
 
-    if(Event::handle('StartShortenUrl', array($long_url,$shortenerName,&$shortenedUrl))){
+    $shortenerName = User_urlshortener_prefs::urlShorteningService($user);
+
+    common_debug("Shortener name = '$shortenerName'");
+
+    if (Event::handle('StartShortenUrl', array($long_url, $shortenerName, &$shortenedUrl))) {
         //URL wasn't shortened, so return the long url
         return $long_url;
-    }else{
+    } else {
         //URL was shortened, so return the result
         return trim($shortenedUrl);
     }