code:
<?php

 /* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
  ·                                                                             ·
  ·                                                                             ·
  ·                             Q V I T T E R                                   ·
  ·                                                                             ·
  ·                      https://git.gnu.io/h2p/Qvitter                         ·
  ·                                                                             ·
  ·                                                                             ·
  ·                                 <o)                                         ·
  ·                                  /_////                                     ·
  ·                                 (____/                                      ·
  ·                                          (o<                                ·
  ·                                   o> \\\\_\                                 ·
  ·                                 \\)   \____)                                ·
  ·                                                                             ·
  ·                                                                             ·
  ·                                                                             ·
  ·  Qvitter 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 three of the License or (at  ·
  ·  your option) any later version.                                            ·
  ·                                                                             ·
  ·  Qvitter is distributed  in hope that  it will be  useful but  WITHOUT ANY  ·
  ·  WARRANTY;  without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>.            ·
  ·                                                                             ·
  ·  Contact h@nnesmannerhe.im if you have any questions.                       ·
  ·                                                                             ·
  · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
class QvitterAction extends ApiAction
{

    function isReadOnly($args)
    {
        return true;
    }

    protected function prepare(array $args=array())
    {
        parent::prepare($args);

        // if we're logged in but we have missing or incorrect csrf cookie, logout
        if(common_logged_in()) {
            $csrf_token = sha1(common_config('qvitter', 'appid').session_id());
            if(!isset($_COOKIE['Qvitter-CSRF']) || $_COOKIE['Qvitter-CSRF'] != $csrf_token) {
                header('Location: '.common_path('').'main/logout');
                die();
            }
        }

        $user = common_current_user();

        return true;
    }

    protected function handle()
    {
        parent::handle();

        $this->showQvitter();

    }

    function showQvitter()
    {

		$logged_in_user_nickname = '';
		$logged_in_user_obj = false;
		$logged_in_user = common_current_user();
		if($logged_in_user) {
			$logged_in_user_nickname = $logged_in_user->nickname;
			$logged_in_user_obj = ApiAction::twitterUserArray($logged_in_user->getProfile());
			}

		$registrationsclosed = false;
		if(common_config('site','closed') == 1 || common_config('site','inviteonly') == 1) {
			$registrationsclosed = true;
			}

		// check if the client's ip address is blocked for registration
		if(is_array(QvitterPlugin::settings("blocked_ips"))) {
			$client_ip_is_blocked = in_array($_SERVER['REMOTE_ADDR'], QvitterPlugin::settings("blocked_ips"));
			}

		$sitetitle = common_config('site','name');
		$siterootdomain = common_config('site','server');
		$qvitterpath = Plugin::staticPath('Qvitter', '');
		$apiroot = common_path('api/', StatusNet::isHTTPS());
		$attachmentroot = common_path('attachment/', StatusNet::isHTTPS());
		$instanceurl = common_path('', StatusNet::isHTTPS());
        $favicon_path = QvitterPlugin::settings("favicon_path");

        // user's browser's language setting
        $user_browser_language = 'en'; // use english if we can't find the browser language
        if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
            $user_browser_language = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
            }

		common_set_returnto(''); // forget this

		// if this is a profile we add a link header for LRDD Discovery (see WebfingerPlugin.php)
		if(substr_count($_SERVER['REQUEST_URI'], '/') == 1) {
			$nickname = substr($_SERVER['REQUEST_URI'],1);
			if(preg_match("/^[a-zA-Z0-9]+$/", $nickname) == 1) {
					$acct = 'acct:'. $nickname .'@'. common_config('site', 'server');
					$url = common_local_url('webfinger') . '?resource='.$acct;
					foreach (array(Discovery::JRD_MIMETYPE, Discovery::XRD_MIMETYPE) as $type) {
						header('Link: <'.$url.'>; rel="'. Discovery::LRDD_REL.'"; type="'.$type.'"');
					}
				}
			}

		?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
		"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
		<html xmlns="http://www.w3.org/1999/xhtml">
			<head>
				<title><?php print $sitetitle; ?></title>
				<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
				<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0">
				<link rel="stylesheet" type="text/css" href="<?php print $qvitterpath; ?>css/qvitter.css?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/css/qvitter.css')); ?>" />
				<link rel="stylesheet" type="text/css" href="<?php print $qvitterpath; ?>css/jquery.minicolors.css" />
                <link rel="apple-touch-icon" sizes="57x57" href="<?php print $favicon_path ?>apple-touch-icon-57x57.png">
                <link rel="apple-touch-icon" sizes="60x60" href="<?php print $favicon_path ?>apple-touch-icon-60x60.png">
                <link rel="apple-touch-icon" sizes="72x72" href="<?php print $favicon_path ?>apple-touch-icon-72x72.png">
                <link rel="apple-touch-icon" sizes="76x76" href="<?php print $favicon_path ?>apple-touch-icon-76x76.png">
                <link rel="apple-touch-icon" sizes="114x114" href="<?php print $favicon_path ?>apple-touch-icon-114x114.png">
                <link rel="apple-touch-icon" sizes="120x120" href="<?php print $favicon_path ?>apple-touch-icon-120x120.png">
                <link rel="apple-touch-icon" sizes="144x144" href="<?php print $favicon_path ?>apple-touch-icon-144x144.png">
                <link rel="apple-touch-icon" sizes="152x152" href="<?php print $favicon_path ?>apple-touch-icon-152x152.png">
                <link rel="apple-touch-icon" sizes="180x180" href="<?php print $favicon_path ?>apple-touch-icon-180x180.png">
                <link rel="icon" type="image/png" href="<?php print $favicon_path ?>favicon-16x16.png" sizes="16x16">
                <link rel="icon" type="image/png" href="<?php print $favicon_path ?>favicon-32x32.png" sizes="32x32">
                <link rel="icon" type="image/png" href="<?php print $favicon_path ?>android-chrome-192x192.png" sizes="192x192">
                <link rel="icon" type="image/png" href="<?php print $favicon_path ?>favicon-96x96.png" sizes="96x96">
                <link rel="manifest" href="<?php print $favicon_path ?>manifest.json">
                <link rel="mask-icon" href="<?php print $favicon_path ?>safari-pinned-tab.svg" color="#a22430">
                <meta name="apple-mobile-web-app-title" content="<?php print $sitetitle; ?>">
                <meta name="application-name" content="<?php print $sitetitle; ?>">
                <meta name="msapplication-TileColor" content="#da532c">
                <meta name="msapplication-TileImage" content="<?php print $favicon_path ?>mstile-144x144.png">
                <meta name="theme-color" content="#ffffff">
				<?php

				// if qvitter is a webapp and this is a users url we add feeds
				if(substr_count($_SERVER['REQUEST_URI'], '/') == 1) {
					$nickname = substr($_SERVER['REQUEST_URI'],1);
					if(preg_match("/^[a-zA-Z0-9]+$/", $nickname) == 1) {
						$user = User::getKV('nickname', $nickname);
						if(!isset($user->id)) {
							//error_log("QVITTER: Could not get user id for user with nickname: $nickname – REQUEST_URI: ".$_SERVER['REQUEST_URI']);
							}
						else {
							print '<link title="Notice feed for '.$nickname.' (Activity Streams JSON)" type="application/stream+json" href="'.$instanceurl.'api/statuses/user_timeline/'.$user->id.'.as" rel="alternate">'."\n";
							print '				<link title="Notice feed for '.$nickname.' (RSS 1.0)" type="application/rdf+xml" href="'.$instanceurl.$nickname.'/rss" rel="alternate">'."\n";
							print '				<link title="Notice feed for '.$nickname.' (RSS 2.0)" type="application/rss+xml" href="'.$instanceurl.'api/statuses/user_timeline/'.$user->id.'.rss" rel="alternate">'."\n";
							print '				<link title="Notice feed for '.$nickname.' (Atom)" type="application/atom+xml" href="'.$instanceurl.'api/statuses/user_timeline/'.$user->id.'.atom" rel="alternate">'."\n";
							print '				<link title="FOAF for '.$nickname.'" type="application/rdf+xml" href="'.$instanceurl.$nickname.'/foaf" rel="meta">'."\n";
							print '				<link href="'.$instanceurl.$nickname.'/microsummary" rel="microsummary">'."\n";

                            // rel="me" for the IndieWeb audience
                            // (no indieweb for users of older gnu social versions)
                            if(method_exists('Profile','getHomepage')) {
                                $user_homepage = $user->getProfile()->getHomepage();
                                $relMes = array(
                                    ['href' => $user->getProfile()->getHomepage(),
                                     'text' => _('Homepage'),
                                     'image' => null],
                                    );
                                Event::handle('OtherAccountProfiles', array($user->getProfile(), &$relMes));
    							foreach ($relMes as $relMe) {
                                    print '				<link href="'.htmlspecialchars($relMe['href']).'" title="'.$relMe['text'].'" rel="me" />'."\n";
                                    }
                                }

							// maybe openid
							if (array_key_exists('OpenID', StatusNet::getActivePlugins())) {
								print '				<link rel="openid2.provider" href="'.common_local_url('openidserver').'"/>'."\n";
								print '				<link rel="openid2.local_id" href="'.$user->getProfile()->profileurl.'"/>'."\n";
								print '				<link rel="openid2.server" href="'.common_local_url('openidserver').'"/>'."\n";
								print '				<link rel="openid2.delegate" href="'.$user->getProfile()->profileurl.'"/>'."\n";
								}
							}
						}
					}
				elseif(substr($_SERVER['REQUEST_URI'],0,7) == '/group/') {
					$group_id_or_name = substr($_SERVER['REQUEST_URI'],7);
					if(stristr($group_id_or_name,'/id')) {
						$group_id_or_name = substr($group_id_or_name, 0, strpos($group_id_or_name,'/id'));
						$group = User_group::getKV('id', $group_id_or_name);
                        if($group instanceof User_group) {
                            $group_name = $group->nickname;
    						$group_id = $group_id_or_name;
                        }
					} else {
						$group = Local_group::getKV('nickname', $group_id_or_name);
                        if($group instanceof Local_group) {
                            $group_id = $group->group_id;
    						$group_name = $group_id_or_name;
                        }
					}
					if(preg_match("/^[a-zA-Z0-9]+$/", $group_id_or_name) == 1 && isset($group_name) && isset($group_id)) {
                ?>

				<link rel="alternate" href="<?php echo htmlspecialchars(common_local_url('ApiTimelineGroup', array('id'=>$group_id, 'format'=>'as'))); ?>" type="application/stream+json" title="Notice feed for '<?php echo htmlspecialchars($group_name); ?>' group (Activity Streams JSON)" />
				<link rel="alternate" href="<?php echo htmlspecialchars(common_local_url('grouprss', array('nickname'=>$group_name))); ?>" type="application/rdf+xml" title="Notice feed for '<?php echo htmlspecialchars($group_name); ?>' group (RSS 1.0)" />
				<link rel="alternate" href="<?php echo htmlspecialchars(common_local_url('ApiTimelineGroup', array('id'=>$group_id, 'format'=>'rss'))); ?>" type="application/rss+xml" title="Notice feed for '<?php echo htmlspecialchars($group_name); ?>' group (RSS 2.0)" />
				<link rel="alternate" href="<?php echo htmlspecialchars(common_local_url('ApiTimelineGroup', array('id'=>$group_id, 'format'=>'atom'))); ?>" type="application/atom+xml" title="Notice feed for '<?php echo htmlspecialchars($group_name); ?>' group (Atom)" />
				<link rel="meta" href="<?php echo htmlspecialchars(common_local_url('foafgroup', array('nickname'=>$group_name))); ?>" type="application/rdf+xml" title="FOAF for '<?php echo htmlspecialchars($group_name); ?>' group" />
                <?php
						}
					}

                // oembed discovery for local notices, and twitter cards
                if(substr($_SERVER['REQUEST_URI'],0,8) == '/notice/'
                && $this->arg('notice')
                && array_key_exists('Oembed', StatusNet::getActivePlugins())) {
                    $notice = Notice::getKV('id', $this->arg('notice'));

                    if($notice instanceof Notice) {
                        $profile = $notice->getProfile();
                        if ($notice->isLocal() && $profile instanceof Profile) {

                            // maybe get thumbnail url
                            $embed_thumbnail_url = false;
                            $attachments = $notice->attachments();
                            if (!empty($attachments)) {
                                foreach ($attachments as $attachment) {
                    				if(is_object($attachment)) {
                                        try {
                                            $thumb = $attachment->getThumbnail();
                    					} catch (ServerException $e) {
                                            //
                                        }
                                        if(!empty($thumb) && method_exists('File_thumbnail','url')) {
                                            try {
                                                $embed_thumbnail_url = File_thumbnail::url($thumb->filename);
                                                break; // only first one
                                            } catch (ClientException $e) {
                                                //
                                            }
                                        }
                                    }
                                }
                            }

                            try {
                                $notice_url = $notice->getUrl();
                                print '<link title="oEmbed" href="'.common_local_url('apiqvitteroembednotice', array('id' => $notice->id, 'format'=>'json')).'?url='.urlencode($notice_url).'" type="application/json+oembed" rel="alternate">'."\n";
                                print '<link title="oEmbed" href="'.common_local_url('apiqvitteroembednotice', array('id' => $notice->id, 'format'=>'xml')).'?url='.urlencode($notice_url).'" type="application/xml+oembed" rel="alternate">'."\n";
                            } catch (Exception $e) {
                                //
                            }

                            // single notice feeds
                            try {
                                $single_notice_json = common_local_url('ApiStatusesShow', array( 'id' => $notice->getID(),'format' => 'json'));
                                $single_notice_atom = common_local_url('ApiStatusesShow', array( 'id' => $notice->getID(),'format' => 'atom'));
                                print '<link title="Single notice (JSON)" href="'.$single_notice_json.'" type="application/stream+json" rel="alternate">'."\n";
                                print '<link title="Single notice (Atom)" href="'.$single_notice_atom.'" type="application/atom+xml" rel="alternate">'."\n";
                            } catch (Exception $e) {
                                //
                            }

                            // twitter cards
                            print '<meta name="twitter:card" content="summary" />'."\n";
                            print '<meta name="twitter:title" content="'.htmlspecialchars($profile->fullname).' (@'.$profile->nickname.')" />'."\n";
                            print '<meta name="twitter:description" content="'.htmlspecialchars($notice->content).'" />'."\n";
                            if($embed_thumbnail_url) {
                                print '<meta name="twitter:image" content="'.$embed_thumbnail_url.'" />'."\n";
                            }

                            // opengraph
                            print '<meta property="og:description" content="'.htmlspecialchars($notice->content).'" />'."\n";
                            print '<meta property="og:site_name" content="'.$sitetitle.'" />'."\n";
                            if($embed_thumbnail_url) {
                                print '<meta property="og:image" content="'.$embed_thumbnail_url.'" />'."\n";
                            }
                        }
                    }
                }

				?>
				<script>

					/*
					@licstart  The following is the entire license notice for the
					JavaScript code in this page.

					Copyright (C) 2015  Hannes Mannerheim and other contributors

					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/>.

					@licend  The above is the entire license notice
					for the JavaScript code in this page.
					*/

                    window.usersLanguageCode = <?php print json_encode($user_browser_language) ?>;
                    window.usersLanguageNameInEnglish = <?php print json_encode(Locale::getDisplayLanguage($user_browser_language, 'en')) ?>;
                    window.englishLanguageData = <?php print file_get_contents(QVITTERDIR.'/locale/en.json'); ?>;
                    window.defaultAvatarStreamSize = <?php print json_encode(Avatar::defaultImage(AVATAR_STREAM_SIZE)) ?>;
                    window.defaultAvatarProfileSize = <?php print json_encode(Avatar::defaultImage(AVATAR_PROFILE_SIZE)) ?>;
					window.textLimit = <?php print json_encode((int)common_config('site','textlimit')) ?>;
					window.registrationsClosed = <?php print json_encode($registrationsclosed) ?>;
					window.thisSiteThinksItIsHttpButIsActuallyHttps = <?php

                        // this is due to a crazy setup at quitter.se, sorry about that
                        $siteSSL = common_config('site', 'ssl');
                        if(isset($_SERVER['HTTPS'])
						&& $_SERVER['HTTPS'] != 'off'
						&& $siteSSL == 'never' ) {
                            $this_site_thinks_it_is_http_but_is_actually_https = true;
                            print 'true';
							}
						else {
                            $this_site_thinks_it_is_http_but_is_actually_https = false;
							print 'false';
							}

					?>;
					window.siteTitle = <?php print json_encode($sitetitle) ?>;
					window.loggedIn = <?php

						$logged_in_user_json = json_encode($logged_in_user_obj);
						$logged_in_user_json = str_replace('http:\/\/quitter.se\/','https:\/\/quitter.se\/',$logged_in_user_json);
						print $logged_in_user_json;

					?>;
					window.timeBetweenPolling = <?php print QvitterPlugin::settings("timebetweenpolling"); ?>;
					window.apiRoot = <?php

                        $api_root = common_path("api/", StatusNet::isHTTPS());
                        if($this_site_thinks_it_is_http_but_is_actually_https) {
                            $api_root = str_replace('http://','https://',$api_root);
                            }
                        print '\''.$api_root.'\'';

                    ?>;
					window.fullUrlToThisQvitterApp = '<?php print $qvitterpath; ?>';
					window.siteRootDomain = '<?php print $siterootdomain; ?>';
					window.siteInstanceURL = '<?php print $instanceurl; ?>';
					window.defaultLinkColor = '<?php print QvitterPlugin::settings("defaultlinkcolor"); ?>';
					window.defaultBackgroundColor = '<?php print QvitterPlugin::settings("defaultbackgroundcolor"); ?>';
					window.siteBackground = '<?php print QvitterPlugin::settings("sitebackground"); ?>';
					window.enableWelcomeText = <?php print json_encode(QvitterPlugin::settings("enablewelcometext")); ?>;
					window.customWelcomeText = <?php print json_encode(QvitterPlugin::settings("customwelcometext")); ?>;
					window.urlShortenerAPIURL = '<?php print QvitterPlugin::settings("urlshortenerapiurl"); ?>';
					window.urlShortenerSignature = '<?php print QvitterPlugin::settings("urlshortenersignature"); ?>';
                    window.urlshortenerFormat = '<?php print QvitterPlugin::settings("urlshortenerformat"); ?>';
					window.commonSessionToken = '<?php print common_session_token(); ?>';
					window.siteMaxThumbnailSize = <?php print common_config('thumbnail', 'maxsize'); ?>;
					window.siteAttachmentURLBase = '<?php print $attachmentroot; ?>';
					window.siteEmail = '<?php print common_config('site', 'email'); ?>';
					window.siteLicenseTitle = '<?php print common_config('license', 'title'); ?>';
					window.siteLicenseURL = '<?php print common_config('license', 'url'); ?>';
					window.customTermsOfUse = <?php print json_encode(QvitterPlugin::settings("customtermsofuse")); ?>;
                    window.siteLocalOnlyDefaultPath = <?php print (common_config('public', 'localonly') ? 'true' : 'false'); ?>;
                    <?php

                        // Get all topics in Qvitter's namespace in Profile_prefs
                        if($logged_in_user) {

                            try {
                                $qvitter_profile_prefs = Profile_prefs::getNamespace(Profile::current(),'qvitter');
                            } catch (Exception $e) {
                                $qvitter_profile_prefs = array();
                            }

                            if(count($qvitter_profile_prefs)>0) {
                                $topic_data = new stdClass();
                                foreach($qvitter_profile_prefs as $pref) {
                                    $topic_data->{$pref->topic} = $pref->data;
                            		}
                                print 'window.qvitterProfilePrefs = '.json_encode($topic_data).';';
                                }
                            else {
                                print 'window.qvitterProfilePrefs = false;';
                                }
                            }

                        // keyboard shortcuts can be disabled
                        $disable_keyboard_shortcuts = false;
                        if($logged_in_user) {
                            try {
                                $disable_keyboard_shortcuts = Profile_prefs::getData($logged_in_user->getProfile(), 'qvitter', 'disable_keyboard_shortcuts');
                                if($disable_keyboard_shortcuts == '1' || $disable_keyboard_shortcuts == 1) {
                                    $disable_keyboard_shortcuts = true;
                                }
                            } catch (Exception $e) {
                                //
                                }
                            }
                        print 'window.disableKeyboardShortcuts = '.var_export($disable_keyboard_shortcuts, true).';';

                    ?>

					// available language files and their last update time
					window.availableLanguages = {<?php

					// scan all files in the locale directory and create a json object with their change date added
					$available_languages = array_diff(scandir(QVITTERDIR.'/locale'), array('..', '.'));
					foreach($available_languages as $lankey=>$lan) {

						$lancode = substr($lan,0,strpos($lan,'.'));

						// for the paranthesis containing language region to work with rtl in ltr enviroment and vice versa, we add a
						// special rtl or ltr html char after the paranthesis
						// this list is incomplete, but if any rtl language gets a regional translation, it will probably be arabic
						$rtl_or_ltr_special_char = '';
						$base_lancode = substr($lancode,0,strpos($lancode,'_'));
						if($base_lancode == 'ar'
						|| $base_lancode == 'fa'
						|| $base_lancode == 'he') {
							$rtl_or_ltr_special_char = '';
							}

						// also make an array with all language names, to use for generating menu
						$languagecodesandnames[$lancode]['english_name'] = Locale::getDisplayName($lancode, 'en');
						$languagecodesandnames[$lancode]['name'] = Locale::getDisplayName($lancode, $lancode);
                        $languagecodesandnames[$lancode]['tooltip'] = $languagecodesandnames[$lancode]['name'].' – '.$languagecodesandnames[$lancode]['english_name'];
                        if($languagecodesandnames[$lancode]['name'] == $languagecodesandnames[$lancode]['english_name']) {
                            $languagecodesandnames[$lancode]['tooltip'] = $languagecodesandnames[$lancode]['english_name'];
                        }

						// ahorita meme only on quitter.es
						if($lancode == 'es_ahorita') {
							if($siterootdomain == 'quitter.es') {
								$languagecodesandnames[$lancode]['name'] = 'español (ahorita)';
								}
							else {
								unset($available_languages[$lankey]);
								unset($languagecodesandnames[$lancode]);
								continue;
								}
							}

						print "\n".'						"'.$lancode.'": "'.$lan.'?changed='.date('YmdHis',filemtime(QVITTERDIR.'/locale/'.$lan)).'",';
						}
						?>

						};

				</script>
				<?php

	            // event for other plugins to use to add head elements to qvitter
	            Event::handle('QvitterEndShowHeadElements', array($this));

				?>
			</head>
			<body class="<?php

            // rights as body classes
            if($logged_in_user) {
                if($logged_in_user_obj['rights']['silence']){
                    print 'has-right-to-silence';
                    }
                if($logged_in_user_obj['rights']['sandbox']){
                    print ' has-right-to-sandbox';
                    }
                }

            ?>" style="background-color:<?php print QvitterPlugin::settings("defaultbackgroundcolor"); ?>">
                <?php

                // add an accessibility toggle link to switch to standard UI, if we're logged in
                if($logged_in_user) {
                    print '<a id="accessibility-toggle-link" href="#"></a>';
                    }

                ?>
				<input id="upload-image-input" class="upload-image-input" type="file" name="upload-image-input">
				<div class="topbar">
					<a href="<?php

                        // if we're logged in, the logo links to the home stream
                        // if logged out it links to the site's public stream
                        if($logged_in_user) {
                            print $instanceurl.$logged_in_user_nickname.'/all';
                            }
                        else {
                            print $instanceurl.'main/public';
                        }

                    ?>"><div id="logo"></div></a><?php

                    // menu for logged in users
                    if($logged_in_user) { ?>
    					<a id="settingslink">
    						<div class="dropdown-toggle">
    							<div class="nav-session" style="background-image:url('<?php print htmlspecialchars($logged_in_user_obj['profile_image_url_profile_size']) ?>')"></div>
    						</div>
    					</a><?php
                        }

                    ?><div id="top-compose" class="hidden"></div>
					<ul class="quitter-settings dropdown-menu">
						<li class="dropdown-caret right">
							<span class="caret-outer"></span>
							<span class="caret-inner"></span>
						</li>
						<li class="fullwidth"><a id="top-menu-profile-link" class="no-hover-card" href="<?php print $instanceurl.$logged_in_user_obj['screen_name']; ?>"><div id="top-menu-profile-link-fullname"><?php print htmlspecialchars($logged_in_user_obj['name']); ?></div><div id="top-menu-profile-link-view-profile"></div></a></li>
						<li class="fullwidth dropdown-divider"></li>
                        <li class="fullwidth"><a id="faq-link"></a></li>
                        <li class="fullwidth"><a id="tou-link"></a></li>
                        <?php

                        if($disable_keyboard_shortcuts === true)  {
                            print '<li class="fullwidth"><a id="shortcuts-link" class="disabled" href="'.$instanceurl.'settings/qvitter"></a></li>';
					        }
                        else {
                            print '<li class="fullwidth"><a id="shortcuts-link"></a></li>';
                            }

                        if (common_config('invite', 'enabled') && !common_config('site', 'closed')) { ?>
							<li class="fullwidth"><a id="invite-link" href="<?php print $instanceurl; ?>main/invite"></a></li>
						<?php } ?>
						<li class="fullwidth"><a id="classic-link"></a></li>
						<li class="fullwidth dropdown-divider"></li>
						<li class="fullwidth"><a id="logout"></a></li>
						<li class="fullwidth language dropdown-divider"></li>
						<?php

						// languages
						foreach($languagecodesandnames as $lancode=>$lan) {
							print '<li class="language"><a class="language-link" data-tooltip="'.$lan['tooltip'].'" data-lang-code="'.$lancode.'">'.$lan['name'].'</a></li>';
							}

						?>
                        <li class="fullwidth language dropdown-divider"></li>
                        <li class="fullwidth"><a href="https://git.gnu.io/h2p/Qvitter/tree/master/locale" target="_blank" id="add-edit-language-link"></a></li>
					</ul>
					<div class="global-nav">
						<div class="global-nav-inner">
							<div class="container">
								<div id="search">
									<input type="text" spellcheck="false" autocomplete="off" name="q" placeholder="Sök" id="search-query" class="search-input">
									<span class="search-icon">
										<button class="icon nav-search" type="submit" tabindex="-1">
											<span> Sök </span>
										</button>
									</span>
								</div>
								<ul class="language-dropdown">
									<li class="dropdown">
										<a class="dropdown-toggle">
											<small></small>
											<span class="current-language"></span>
											<b class="caret"></b>
										</a>
										<ul class="dropdown-menu">
											<li class="dropdown-caret right">
												<span class="caret-outer"></span>
												<span class="caret-inner"></span>
											</li>
											<?php

											// languages
											foreach($languagecodesandnames as $lancode=>$lan) {
												print '<li><a class="language-link" data-tooltip="'.$lan['english_name'].'" data-lang-code="'.$lancode.'">'.$lan['name'].'</a></li>';
												}

											?>
										</ul>
									</li>
								</ul>
							</div>
						</div>
					</div>
				</div>
                <div id="no-js-error">Please enable javascript to use this site.<script>var element = document.getElementById('no-js-error'); element.parentNode.removeChild(element);</script></div>
				<div id="page-container">
					<?php

					$site_notice = common_config('site', 'notice');
					if(!empty($site_notice)) {
						print '<div id="site-notice">'.common_config('site', 'notice').'</div>';
						}

                    // welcome text, login and register container if logged out
                    if($logged_in_user === null) { ?>
                        <div class="front-welcome-text <?php if ($registrationsclosed) { print 'registrations-closed'; } ?>"></div>
                        <div id="login-register-container">
    						<div id="login-content">
    							<form id="form_login" class="form_settings" action="<?php print common_local_url('qvitterlogin'); ?>" method="post">
    								<div id="username-container">
    									<input id="nickname" name="nickname" type="text" value="<?php print $logged_in_user_nickname ?>" tabindex="1" />
    								</div>
    								<table class="password-signin"><tbody><tr>
    									<td class="flex-table-primary">
    										<div class="placeholding-input">
    											<input id="password" name="password" type="password" tabindex="2" value="" />
    										</div>
    									</td>
    									<td class="flex-table-secondary">
    										<button class="submit" type="submit" id="submit-login" tabindex="4"></button>
    									</td>
    								</tr></tbody></table>
    								<div id="remember-forgot">
    									<input type="checkbox" id="rememberme" name="rememberme" value="yes" tabindex="3" checked="checked"> <span id="rememberme_label"></span> · <a id="forgot-password" href="<?php print $instanceurl ?>main/recoverpassword" ></a>
    									<input type="hidden" id="token" name="token" value="<?php print common_session_token(); ?>">
    									<?php

    									if (array_key_exists('OpenID', StatusNet::getActivePlugins())) {
    										print '<a href="'.$instanceurl.'main/openid" id="openid-login" title="OpenID" donthijack>OpenID</a>';
    										}

    									?>
    								</div>
    							</form>
    						</div>
    						<?php
    						if($registrationsclosed === false && $client_ip_is_blocked === false) {
    						?><div class="front-signup">
    							<h2></h2>
    							<div class="signup-input-container"><input placeholder="" type="text" name="user[name]" autocomplete="off" class="text-input" id="signup-user-name"></div>
    							<div class="signup-input-container"><input placeholder="" type="text" name="user[email]" autocomplete="off" id="signup-user-email"></div>
    							<div class="signup-input-container"><input placeholder="" type="password" name="user[user_password]" class="text-input" id="signup-user-password"></div>
    							<button id="signup-btn-step1" class="signup-btn" type="submit"></button>
    						</div>
                            <div id="other-servers-link"></div><?php }
                            ?><div id="qvitter-notice-logged-out"><?php print common_config('site', 'qvitternoticeloggedout'); ?></div><?php

                            // event for other plugins to add html to the logged in sidebar
                            Event::handle('QvitterEndShowSidebarLoggedOut', array($this));

                            ?></div><?php
                        }

                    // box containing the logged in users queet count and compose form
                    if($logged_in_user) { ?>
                        <div id="user-container" style="display:none;">
    						<div id="user-header" style="background-image:url('<?php print htmlspecialchars($logged_in_user_obj['cover_photo']) ?>')">
    							<div id="mini-logged-in-user-cog-wheel"></div>
    							<div class="profile-header-inner-overlay"></div>
    							<div id="user-avatar-container"><img id="user-avatar" src="<?php print htmlspecialchars($logged_in_user_obj['profile_image_url_profile_size']) ?>" /></div>
    							<div id="user-name"><?php print htmlspecialchars($logged_in_user_obj['name']) ?></div>
    							<div id="user-screen-name"><?php print htmlspecialchars($logged_in_user_obj['screen_name']) ?></div>
    						</div>
    						<ul id="user-body">
    							<li><a href="<?php print $instanceurl.$logged_in_user->nickname ?>" id="user-queets"><span class="label"></span><strong><?php print $logged_in_user_obj['statuses_count'] ?></strong></a></li>
    							<li><a href="<?php print $instanceurl.$logged_in_user->nickname ?>/subscriptions" id="user-following"><span class="label"></span><strong><?php print $logged_in_user_obj['friends_count'] ?></strong></a></li>
    							<li><a href="<?php print $instanceurl.$logged_in_user->nickname ?>/groups" id="user-groups"><span class="label"></span><strong><?php print $logged_in_user_obj['groups_count'] ?></strong></a></li>
    						</ul>
    						<div id="user-footer">
    							<div id="user-footer-inner">
    								<div id="queet-box" class="queet-box queet-box-syntax" data-start-text=""></div>
    								<div class="syntax-middle"></div>
    								<div class="syntax-two" contenteditable="true"></div>
    								<div class="mentions-suggestions"></div>
    								<div class="queet-toolbar">
    									<div class="queet-box-extras">
    										<button class="upload-image"></button>
    										<button class="shorten disabled">URL</button>
    									</div>
    									<div class="queet-button">
    										<span class="queet-counter"></span>
    										<button></button>
    									</div>
    								</div>
    							</div>
    						</div>
                            <div id="main-menu" class="menu-container"><?php

                                    if($logged_in_user) {
                                        ?><a href="<?php print $instanceurl.$logged_in_user->nickname ?>/all" class="stream-selection friends-timeline"><i class="chev-right"></i></a>
            							<a href="<?php print $instanceurl.$logged_in_user->nickname ?>/notifications" class="stream-selection notifications"><span id="unseen-notifications"></span><i class="chev-right"></i></a>
            							<a href="<?php print $instanceurl.$logged_in_user->nickname ?>" class="stream-selection my-timeline"><i class="chev-right"></i></a>
            							<a href="<?php print $instanceurl.$logged_in_user->nickname ?>/favorites" class="stream-selection favorites"><i class="chev-right"></i></a>
            							<a href="<?php print $instanceurl ?>main/public" class="stream-selection public-timeline"><i class="chev-right"></i></a>
            							<a href="<?php print $instanceurl ?>main/all" class="stream-selection public-and-external-timeline"><i class="chev-right"></i></a>
                                        <?php
                                        }
                                ?>
        						</div>
        						<div class="menu-container" id="bookmark-container"></div>
                                <div class="menu-container" id="history-container"></div>
                                <div id="clear-history"></div>
        						<div id="qvitter-notice"><?php print common_config('site', 'qvitternotice'); ?></div><?php

                	            // event for other plugins to add html to the logged in sidebar
                	            Event::handle('QvitterEndShowSidebarLoggedIn', array($this));

        				        ?></div><?php
                            } ?>

                    <div id="feed">
						<div id="feed-header">
							<div id="feed-header-inner">
								<h2>
                                    <span id="stream-header"></span>
                                </h2>
								<div class="reload-stream"></div>
							</div>
                            <div id="feed-header-description"></div>
						</div>
						<div id="new-queets-bar-container" class="hidden"><div id="new-queets-bar"></div></div>
						<div id="feed-body"></div>
					</div>
                    <div id="hidden-html"><?php

                        // adds temporary support for microformats and linkbacks on the notice page
                    	if(substr($_SERVER['REQUEST_URI'],0,8) == '/notice/' && $this->arg('notice')) {
                    		echo '<ol class="notices xoxo">';
                            if($notice instanceof Notice) {
                    			$widget = new NoticeListItem($notice, $this);
                    			$widget->show();
                    			$this->flush();
                            }
                    		echo '</ol>';
                    	}

                        Event::handle('QvitterHiddenHtml', array($this));

                    ?></div>
					<div id="footer"><div id="footer-spinner-container"></div></div>
				</div>
				<script type="text/javascript" src="<?php print $qvitterpath; ?>js/lib/jquery-2.1.4.min.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/lib/jquery-2.1.4.min.js')); ?>"></script>
				<script type="text/javascript" src="<?php print $qvitterpath; ?>js/lib/jquery-ui.min.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/lib/jquery-ui.min.js')); ?>"></script>
				<script type="text/javascript" src="<?php print $qvitterpath; ?>js/lib/jquery.minicolors.min.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/lib/jquery.minicolors.min.js')); ?>"></script>
				<script type="text/javascript" src="<?php print $qvitterpath; ?>js/lib/jquery.jWindowCrop.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/lib/jquery.jWindowCrop.js')); ?>"></script>
				<script type="text/javascript" src="<?php print $qvitterpath; ?>js/lib/load-image.min.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/lib/load-image.min.js')); ?>"></script>
				<script type="text/javascript" src="<?php print $qvitterpath; ?>js/lib/xregexp-all-3.0.0-pre.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/lib/xregexp-all-3.0.0-pre.js')); ?>"></script>
                <script type="text/javascript" src="<?php print $qvitterpath; ?>js/lib/lz-string.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/lib/lz-string.js')); ?>"></script>
                <script type="text/javascript" src="<?php print $qvitterpath; ?>js/lib/bowser.min.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/lib/bowser.min.js')); ?>"></script>
				<script charset="utf-8" type="text/javascript" src="<?php print $qvitterpath; ?>js/dom-functions.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/dom-functions.js')); ?>"></script>
				<script charset="utf-8" type="text/javascript" src="<?php print $qvitterpath; ?>js/misc-functions.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/misc-functions.js')); ?>"></script>
				<script charset="utf-8" type="text/javascript" src="<?php print $qvitterpath; ?>js/ajax-functions.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/ajax-functions.js')); ?>"></script>
                <script charset="utf-8" type="text/javascript" src="<?php print $qvitterpath; ?>js/stream-router.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/stream-router.js')); ?>"></script>
				<script charset="utf-8" type="text/javascript" src="<?php print $qvitterpath; ?>js/qvitter.js?changed=<?php print date('YmdHis',filemtime(QVITTERDIR.'/js/qvitter.js')); ?>"></script>
				<?php

					// event for other plugins to add scripts to qvitter
					Event::handle('QvitterEndShowScripts', array($this));

					// we might have custom javascript in the config file that we want to add
					if(QvitterPlugin::settings('js')) {
						print '<script type="text/javascript">'.QvitterPlugin::settings('js').'</script>';
					}

				?>
			<div id="dynamic-styles">
				<style>
					a, a:visited, a:active,
					ul.stats li:hover a,
					ul.stats li:hover a strong,
					#user-body a:hover div strong,
					#user-body a:hover div div,
					.permalink-link:hover,
					.stream-item.expanded > .queet .stream-item-expand,
					.stream-item-footer .with-icn .requeet-text a b:hover,
					.queet-text span.attachment.more,
					.stream-item-header .created-at a:hover,
					.stream-item-header a.account-group:hover .name,
					.queet:hover .stream-item-expand,
					.show-full-conversation:hover,
					#new-queets-bar,
					.menu-container div,
					.cm-mention, .cm-tag, .cm-group, .cm-url, .cm-email,
					div.syntax-middle span,
					#user-body strong,
					ul.stats,
					.stream-item:not(.temp-post) ul.queet-actions li .icon:not(.is-mine):hover:before,
					.show-full-conversation,
					#user-body #user-queets:hover .label,
					#user-body #user-groups:hover .label,
					#user-body #user-following:hover .label,
					ul.stats a strong,
					.queet-box-extras button,
					#openid-login:hover:after,
                    .post-to-group,
                    .stream-item-header .addressees .reply-to .h-card.not-mentioned-inline {
						color:/*COLORSTART*/<?php print QvitterPlugin::settings("defaultlinkcolor"); ?>/*COLOREND*/;
						}
					#unseen-notifications,
					.stream-item.notification.not-seen > .queet::before,
					#top-compose,
					#logo,
					.queet-toolbar button,
					#user-header,
					.profile-header-inner,
					.topbar,
					.menu-container,
					.member-button.member,
					.external-follow-button.following,
					.qvitter-follow-button.following,
					.save-profile-button,
					.crop-and-save-button,
					.topbar .global-nav.show-logo:before,
					.topbar .global-nav.pulse-logo:before,
                    .dropdown-menu li:not(.dropdown-caret) a:hover {
						background-color:/*BACKGROUNDCOLORSTART*/<?php print QvitterPlugin::settings("defaultlinkcolor"); ?>/*BACKGROUNDCOLOREND*/;
						}
					.queet-box-syntax[contenteditable="true"]:focus,
                    .stream-item.selected-by-keyboard::before {
						border-color:/*BORDERCOLORSTART*/#999999/*BORDERCOLOREND*/;
						}
					#user-footer-inner,
					.inline-reply-queetbox,
					#popup-faq #faq-container p.indent {
						background-color:/*LIGHTERBACKGROUNDCOLORSTART*/rgb(205,230,239)/*LIGHTERBACKGROUNDCOLOREND*/;
						}
					#user-footer-inner,
					.queet-box,
					.queet-box-syntax[contenteditable="true"],
					.inline-reply-queetbox,
					span.inline-reply-caret,
				    .stream-item.expanded .stream-item.first-visible-after-parent,
					#popup-faq #faq-container p.indent,
                    .post-to-group,
                    .quoted-notice:hover,
                    .oembed-item:hover,
                    .stream-item:hover:not(.expanded) .quoted-notice:hover,
                    .stream-item:hover:not(.expanded) .oembed-item:hover {
						border-color:/*LIGHTERBORDERCOLORSTART*/rgb(155,206,224)/*LIGHTERBORDERCOLOREND*/;
						}
					span.inline-reply-caret .caret-inner {
						border-bottom-color:/*LIGHTERBORDERBOTTOMCOLORSTART*/rgb(205,230,239)/*LIGHTERBORDERBOTTOMCOLOREND*/;
						}

					.modal-close .icon,
					.chev-right,
					.close-right,
					button.icon.nav-search,
					.member-button .join-text i,
					.external-member-button .join-text i,
					.external-follow-button .follow-text i,
					.qvitter-follow-button .follow-text i,
					#logo,
					.upload-cover-photo,
					.upload-avatar,
					.upload-background-image,
					button.shorten i,
					.reload-stream,
					.topbar .global-nav:before,
					.stream-item.notification.repeat .dogear,
					.stream-item.notification.like .dogear,
					.ostatus-link,
					.close-edit-profile-window {
						background-image: url("<?php print QvitterPlugin::settings("sprite"); ?>");
						background-size: 500px 1329px;
						}
					@media (max-width: 910px) {
						#search-query,
						.menu-container a,
						.menu-container a.current,
						.stream-selection.friends-timeline:after,
						.stream-selection.notifications:after,
						.stream-selection.my-timeline:after,
						.stream-selection.public-timeline:after {
							background-image: url("<?php print QvitterPlugin::settings("sprite"); ?>");
							background-size: 500px 1329px;
							}
						}

				</style>
			</div>
			</body>
		</html>

			<?php
    }

}


code:
<?php

 /* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
  ·                                                                             ·
  ·                                                                             ·
  ·                             Q V I T T E R                                   ·
  ·                                                                             ·
  ·                      https://git.gnu.io/h2p/Qvitter                         ·
  ·                                                                             ·
  ·                                                                             ·
  ·                                 <o)                                         ·
  ·                                  /_////                                     ·
  ·                                 (____/                                      ·
  ·                                          (o<                                ·
  ·                                   o> \\\\_\                                 ·
  ·                                 \\)   \____)                                ·
  ·                                                                             ·
  ·                                                                             ·
  ·                                                                             ·
  ·  Qvitter 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 three of the License or (at  ·
  ·  your option) any later version.                                            ·
  ·                                                                             ·
  ·  Qvitter is distributed  in hope that  it will be  useful but  WITHOUT ANY  ·
  ·  WARRANTY;  without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>.            ·
  ·                                                                             ·
  ·  Contact h@nnesmannerhe.im if you have any questions.                       ·
  ·                                                                             ·
  · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

class QvitterAdminSettingsAction extends AdminPanelAction
{
    /**
     * Returns the page title
     *
     * @return string page title
     */
    function title()
    {
        // TRANS: Page title for site-wide notice tab in admin panel.
        return _('Qvitter Sidebar Notice');
    }

    /**
     * Instructions for using this form.
     *
     * @return string instructions
     */
    function getInstructions()
    {
        // TRANS: Instructions for site-wide notice tab in admin panel.
        return _('Edit notice in Qvitter\'s sidebar');
    }

    /**
     * Show the site notice admin panel form
     *
     * @return void
     */
    function showForm()
    {
        $form = new QvitterNoticeAdminPanelForm($this);
        $form->show();
        return;
    }

    /**
     * Save settings from the form
     *
     * @return void
     */
    function saveSettings()
    {
        $qvitterNotice = $this->trimmed('qvitter-notice');
        $qvitterNoticeLoggedOut = $this->trimmed('qvitter-notice-logged-out');

        // assert(all values are valid);
        // This throws an exception on validation errors

        $this->validate($qvitterNotice);
        $this->validate($qvitterNoticeLoggedOut);

        $config = new Config();

        $result = Config::save('site', 'qvitternotice', $qvitterNotice);
        $result = Config::save('site', 'qvitternoticeloggedout', $qvitterNoticeLoggedOut);

        if (!$result) {
            // TRANS: Server error displayed when saving a sidebar notice was impossible.
            $this->ServerError(_('Unable to save qvitter sidebar notice.'));
        }
    }

    function validate(&$qvitterNotice)
    {
        // Validate notice text

	//The column 'value' in table 'config' is TEXT
        if (mb_strlen($qvitterNotice) > 21844)  {
            $this->clientError(
                // TRANS: Client error displayed when a sidebar notice was longer than allowed.
                _('Maximum length for the sidebar notice is 21844 characters.')
            );
        }
    }
}

class QvitterNoticeAdminPanelForm extends AdminForm
{
    /**
     * ID of the form
     *
     * @return int ID of the form
     */

    function id()
    {
        return 'form_qvitter_notice_admin_panel';
    }

    /**
     * class of the form
     *
     * @return string class of the form
     */

    function formClass()
    {
        return 'form_settings';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */

    function action()
    {
        return common_local_url('qvitteradminsettings');
    }

    /**
     * Data elements of the form
     *
     * @return void
     */

    function formData()
    {
        $this->out->elementStart('ul', 'form_data');

        $this->out->elementStart('li');
        $this->out->textarea(
            'qvitter-notice',
            // TRANS: Label for sidebar notice text field in admin panel.
            _('Qvitter sidebar notice text'),
            common_config('site', 'qvitternotice'),
            // TRANS: Tooltip for sidebar notice text field in admin panel.
            _('Qvitter\'s sidebar notice text (21,844 characters maximum; HTML allowed)')
        );
        $this->out->elementEnd('li');

        $this->out->elementEnd('ul');

        $this->out->elementStart('ul', 'form_data');

        $this->out->elementStart('li');
        $this->out->textarea(
            'qvitter-notice-logged-out',
            // TRANS: Label for sidebar notice text field in admin panel.
            _('Qvitter sidebar notice text (logged out)'),
            common_config('site', 'qvitternoticeloggedout'),
            // TRANS: Tooltip for sidebar notice text field in admin panel.
            _('Qvitter\'s sidebar notice text, when logged out (21,844 characters maximum; HTML allowed)')
        );
        $this->out->elementEnd('li');

        $this->out->elementEnd('ul');
    }

    /**
     * Action elements
     *
     * @return void
     */

    function formActions()
    {
        $this->out->submit(
            'submit',
            // TRANS: Button text for saving sidebar notice in admin panel.
            _m('BUTTON','Save'),
            'submit',
            null,
            // TRANS: Button title to save sidebar notice in admin panel.
            _('Save sidebar notice.')
        );
    }
}

license: mit


code:
<?php

 /* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
  ·                                                                             ·
  ·                                                                             ·
  ·                             Q V I T T E R                                   ·
  ·                                                                             ·
  ·                      https://git.gnu.io/h2p/Qvitter                         ·
  ·                                                                             ·
  ·                                                                             ·
  ·                                 <o)                                         ·
  ·                                  /_////                                     ·
  ·                                 (____/                                      ·
  ·                                          (o<                                ·
  ·                                   o> \\\\_\                                 ·
  ·                                 \\)   \____)                                ·
  ·                                                                             ·
  ·                                                                             ·
  ·                                                                             ·
  ·  Qvitter 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 three of the License or (at  ·
  ·  your option) any later version.                                            ·
  ·                                                                             ·
  ·  Qvitter is distributed  in hope that  it will be  useful but  WITHOUT ANY  ·
  ·  WARRANTY;  without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>.            ·
  ·                                                                             ·
  ·  Contact h@nnesmannerhe.im if you have any questions.                       ·
  ·                                                                             ·
  · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */

if (!defined('GNUSOCIAL')) { exit(1); }

class QvitterLoginAction extends FormAction
{
    protected $needLogin = false;

    /**
     * Prepare page to run
     *
     *
     * @param $args
     * @return string title
     */
    protected function prepare(array $args=array())
    {
        // @todo this check should really be in index.php for all sensitive actions
        $ssl = common_config('site', 'ssl');
        if (empty($_SERVER['HTTPS']) && ($ssl == 'always' || $ssl == 'sometimes')) {
            common_redirect(common_local_url('login'));
        }

        return parent::prepare($args);
    }

    /**
     * Handle input, produce output
     *
     * Switches on request method; either shows the form or handles its input.
     *
     * @return void
     */
    protected function handle()
    {
        if (common_is_real_login()) {
            common_redirect(common_local_url('all', array('nickname' => $this->scoped->nickname)), 307);
        }

        return parent::handle();
    }

    /**
     * Check the login data
     *
     * Determines if the login data is valid. If so, logs the user
     * in, and redirects to the 'with friends' page, or to the stored
     * return-to URL.
     *
     * @return void
     */
    protected function handlePost()
    {
        parent::handlePost();

        // XXX: login throttle

        $nickname = $this->trimmed('nickname');
        $password = $this->arg('password');

        $user = common_check_user($nickname, $password);

        if (!$user instanceof User) {
            // TRANS: Form validation error displayed when trying to log in with incorrect credentials.
            throw new ServerException(_('Incorrect username or password.'));
        }

        // success!
        if (!common_set_user($user)) {
            // TRANS: Server error displayed when during login a server error occurs.
            throw new ServerException(_('Error setting user. You are probably not authorized.'));
        }

        common_real_login(true);
        $this->updateScopedProfile();

        if ($this->boolean('rememberme')) {
            common_rememberme($user);
        }

        // make sure we have a unique app id for this Qvitter installation in config
        // to use for creating a csrf token
		if(common_config('qvitter', 'appid') == false) {
            Config::save('qvitter', 'appid', sha1(common_random_hexstr(16)));
		}

        // set csrf-cookie
        $csrf_token = sha1(common_config('qvitter', 'appid').session_id());
        common_set_cookie('Qvitter-CSRF', $csrf_token, time() + 60*60*24*30); // 1 month

        $url = common_get_returnto();

        if ($url) {
            // We don't have to return to it again
            common_set_returnto(null);
            $url = common_inject_session($url);
        } else {
            $url = common_local_url('all',
                                    array('nickname' => $this->scoped->nickname));
        }

        common_redirect($url, 303);
    }

    function showPage()
    {

		QvitterAction::showQvitter();

    }

}


code:
<?php

 /* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
  ·                                                                             ·
  ·                                                                             ·
  ·                             Q V I T T E R                                   ·
  ·                                                                             ·
  ·                      https://git.gnu.io/h2p/Qvitter                         ·
  ·                                                                             ·
  ·                                                                             ·
  ·                                 <o)                                         ·
  ·                                  /_////                                     ·
  ·                                 (____/                                      ·
  ·                                          (o<                                ·
  ·                                   o> \\\\_\                                 ·
  ·                                 \\)   \____)                                ·
  ·                                                                             ·
  ·                                                                             ·
  ·                                                                             ·
  ·  Qvitter 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 three of the License or (at  ·
  ·  your option) any later version.                                            ·
  ·                                                                             ·
  ·  Qvitter is distributed  in hope that  it will be  useful but  WITHOUT ANY  ·
  ·  WARRANTY;  without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>.            ·
  ·                                                                             ·
  ·  Contact h@nnesmannerhe.im if you have any questions.                       ·
  ·                                                                             ·
  · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

class QvitterSettingsAction extends SettingsAction
{
    /**
     * Title of the page
     *
     * @return string Page title
     */
    function title()
    {
        // TRANS: Page title.
        return _m('Qvitter settings');
    }

    /**
     * Instructions for use
     *
     * @return string Instructions for use
     */

    function getInstructions()
    {
        // TRANS: Page instructions.
        return _m('Qvitter Settings');
    }

    /**
     * Show the form for Qvitter
     *
     * @return void
     */
    function showContent()
    {
        $user = common_current_user();

		if(QvitterPlugin::settings('enabledbydefault')) {
			try {
				$disable_enable_prefs = Profile_prefs::getData($user->getProfile(), 'qvitter', 'disable_qvitter');
			} catch (NoResultException $e) {
				$disable_enable_prefs = false;
			}
		} else {
			try {
				$disable_enable_prefs = Profile_prefs::getData($user->getProfile(), 'qvitter', 'enable_qvitter');
			} catch (NoResultException $e) {
				$disable_enable_prefs = false;
			}
		}

		try {
			$hide_replies_prefs = Profile_prefs::getData($user->getProfile(), 'qvitter', 'hide_replies');
		} catch (NoResultException $e) {
			$hide_replies_prefs = false;
		}

		try {
			$disable_keyboard_shortcuts = Profile_prefs::getData($user->getProfile(), 'qvitter', 'disable_keyboard_shortcuts');
		} catch (NoResultException $e) {
			$disable_keyboard_shortcuts = false;
		}

        $form = new QvitterPrefsForm($this, $disable_enable_prefs, $hide_replies_prefs, $disable_keyboard_shortcuts);

        $form->show();
    }

    /**
     * Handler method
     *
     * @param array $argarray is ignored since it's now passed in in prepare()
     *
     * @return void
     */

    function handlePost()
    {
        $user = common_current_user();

		if(QvitterPlugin::settings('enabledbydefault')) {
			Profile_prefs::setData($user->getProfile(), 'qvitter', 'disable_qvitter', $this->boolean('disable_qvitter'));
			}
		else {
			Profile_prefs::setData($user->getProfile(), 'qvitter', 'enable_qvitter', $this->boolean('enable_qvitter'));
			}

        Profile_prefs::setData($user->getProfile(), 'qvitter', 'hide_replies', $this->boolean('hide_replies'));

        Profile_prefs::setData($user->getProfile(), 'qvitter', 'disable_keyboard_shortcuts', $this->boolean('disable_keyboard_shortcuts'));

        // TRANS: Confirmation shown when user profile settings are saved.
        $this->showForm(_('Settings saved.'), true);

        return;
    }
}

class QvitterPrefsForm extends Form
{
    var $disable_enable_prefs;
    var $hide_replies_prefs;
    var $disable_keyboard_shortcuts;

    function __construct($out, $disable_enable_prefs, $hide_replies_prefs, $disable_keyboard_shortcuts)
    {
        parent::__construct($out);
        $this->disable_enable_prefs = $disable_enable_prefs;
        $this->hide_replies_prefs = $hide_replies_prefs;
        $this->disable_keyboard_shortcuts = $disable_keyboard_shortcuts;
    }

    /**
     * Visible or invisible data elements
     *
     * Display the form fields that make up the data of the form.
     * Sub-classes should overload this to show their data.
     *
     * @return void
     */

    function formData()
    {

		if(QvitterPlugin::settings('enabledbydefault')) {
			$enabledisable = 'disable_qvitter';
			$enabledisablelabel = _('Disable Qvitter');
		} else {
			$enabledisable = 'enable_qvitter';
			$enabledisablelabel = _('Enable Qvitter');
		}

        $this->elementStart('fieldset');
        $this->elementStart('ul', 'form_data');
        $this->elementStart('li');
        $this->checkbox($enabledisable,
                        $enabledisablelabel,
                        (!empty($this->disable_enable_prefs)));
        $this->elementEnd('li');
        $this->elementEnd('ul');
        $this->elementEnd('fieldset');

        $this->elementStart('fieldset');
        $this->elementStart('ul', 'form_data');
        $this->elementStart('li');
        $this->checkbox('hide_replies',
                        _('Hide replies to people I\'m not following'),
                        (!empty($this->hide_replies_prefs)));
        $this->elementEnd('li');
        $this->elementEnd('ul');
        $this->elementEnd('fieldset');

        $this->elementStart('fieldset');
        $this->elementStart('ul', 'form_data');
        $this->elementStart('li');
        $this->checkbox('disable_keyboard_shortcuts',
                        _('Disable keyboard shortcuts'),
                        (!empty($this->disable_keyboard_shortcuts)));
        $this->elementEnd('li');
        $this->elementEnd('ul');
        $this->elementEnd('fieldset');
    }

    /**
     * Buttons for form actions
     *
     * Submit and cancel buttons (or whatever)
     * Sub-classes should overload this to show their own buttons.
     *
     * @return void
     */

    function formActions()
    {
        $this->submit('submit', _('Save'));
    }

    /**
     * ID of the form
     *
     * Should be unique on the page. Sub-classes should overload this
     * to show their own IDs.
     *
     * @return int ID of the form
     */

    function id()
    {
        return 'form_qvitter_prefs';
    }

    /**
     * Action of the form.
     *
     * URL to post to. Should be overloaded by subclasses to give
     * somewhere to post to.
     *
     * @return string URL to post to
     */

    function action()
    {
        return common_local_url('qvittersettings');
    }

    /**
     * Class of the form. May include space-separated list of multiple classes.
     *
     * @return string the form's class
     */

    function formClass()
    {
        return 'form_settings';
    }
}


code:
<?php
/**
 *
 * Notification stream
 *
 */

if (!defined('GNUSOCIAL') && !defined('STATUSNET')) { exit(1); }

class NotificationStream
{
    protected $target  = null;

    /**
     * Constructor
     *
     * @param Profile $target Profile to get a stream for
     */
    function __construct(Profile $target)
    {
        $this->target  = $target;
    }

    /**
     * Get IDs in a range
     *
     * @param int $offset   Offset from start
     * @param int $limit    Limit of number to get
     * @param int $since_id Since this notice
     * @param int $max_id   Before this notice
     *
     * @return Array IDs found
     */
    function getNotificationIds($offset, $limit, $since_id, $max_id)
    {

        $current_profile = Profile::current();

        $notification = new QvitterNotification();
        $notification->selectAdd();
        $notification->selectAdd('id');
        $notification->whereAdd(sprintf('qvitternotification.to_profile_id = "%s"', $notification->escape($this->target->id)));
        $notification->whereAdd(sprintf('qvitternotification.created >= "%s"', $notification->escape($this->target->created)));

        // if the user only want notifications from users they follow
        $only_show_notifications_from_users_i_follow = Profile_prefs::getConfigData($current_profile, 'qvitter', 'only_show_notifications_from_users_i_follow');
        if($only_show_notifications_from_users_i_follow == '1') {
            $notification->whereAdd(sprintf('qvitternotification.from_profile_id IN (SELECT subscribed FROM subscription WHERE subscriber = %u)', $current_profile->id));
            }

        // the user might have opted out from notifications from profiles they have muted
        $hide_notifications_from_muted_users = Profile_prefs::getConfigData($current_profile, 'qvitter', 'hide_notifications_from_muted_users');
        if($hide_notifications_from_muted_users == '1') {
            $muted_ids = QvitterMuted::getMutedIDs($current_profile->id,0,10000); // get all (hopefully not more than 10 000...)
            if($muted_ids !== false && count($muted_ids) > 0) {
                $ids_imploded = implode(',',$muted_ids);
                $notification->whereAdd('qvitternotification.from_profile_id NOT IN ('.$ids_imploded.')');
                }
            }

        // the user might have opted out from certain notification types
        $disable_notify_replies_and_mentions = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_replies_and_mentions');
        $disable_notify_favs = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_favs');
        $disable_notify_repeats = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_repeats');
        $disable_notify_follows = Profile_prefs::getConfigData($current_profile, 'qvitter', 'disable_notify_follows');
        if($disable_notify_replies_and_mentions == '1') {
            $notification->whereAdd('qvitternotification.ntype != "mention"');
            $notification->whereAdd('qvitternotification.ntype != "reply"');
            }
        if($disable_notify_favs == '1') {
            $notification->whereAdd('qvitternotification.ntype != "like"');
            }
        if($disable_notify_repeats == '1') {
            $notification->whereAdd('qvitternotification.ntype != "repeat"');
            }
        if($disable_notify_follows == '1') {
            $notification->whereAdd('qvitternotification.ntype != "follow"');
            }

        $notification->limit($offset, $limit);
        $notification->orderBy('qvitternotification.created DESC');

		if($since_id) {
	        $notification->whereAdd(sprintf('qvitternotification.id > %d', $notification->escape($since_id)));
			}

		if($max_id) {
	        $notification->whereAdd(sprintf('qvitternotification.id <= %d', $notification->escape($max_id)));
			}

        if (!$notification->find()) {
            return array();
        }

        $ids = $notification->fetchAll('id');

        return $ids;
    }

    function getNotifications($offset, $limit, $sinceId, $maxId)
    {

        $all = array();

        do {

            $ids = $this->getNotificationIds($offset, $limit, $sinceId, $maxId);

            $notifications = QvitterNotification::pivotGet('id', $ids);

            // By default, takes out false values

            $notifications = array_filter($notifications);

            $all = array_merge($all, $notifications);

            if (count($notifications < count($ids))) {
                $offset += $limit;
                $limit  -= count($notifications);
            }

        } while (count($notifications) < count($ids) && count($ids) > 0);

        return new ArrayWrapper($all);
    }

}


code:
<?php

 /* · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
  ·                                                                             ·
  ·                                                                             ·
  ·                             Q V I T T E R                                   ·
  ·                                                                             ·
  ·                      https://git.gnu.io/h2p/Qvitter                         ·
  ·                                                                             ·
  ·                                                                             ·
  ·                                 <o)                                         ·
  ·                                  /_////                                     ·
  ·                                 (____/                                      ·
  ·                                          (o<                                ·
  ·                                   o> \\\\_\                                 ·
  ·                                 \\)   \____)                                ·
  ·                                                                             ·
  ·                                                                             ·
  ·                                                                             ·
  ·  Qvitter 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 three of the License or (at  ·
  ·  your option) any later version.                                            ·
  ·                                                                             ·
  ·  Qvitter is distributed  in hope that  it will be  useful but  WITHOUT ANY  ·
  ·  WARRANTY;  without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>.            ·
  ·                                                                             ·
  ·  Contact h@nnesmannerhe.im if you have any questions.                       ·
  ·                                                                             ·
  · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */

if (!defined('STATUSNET')) {
    exit(1);
}

class PublicAndExternalNoticeStream extends ScopingNoticeStream
{
    function __construct($profile=null)
    {

        parent::__construct(new CachingNoticeStream(new RawPublicAndExternalNoticeStream(),
                                                    'publicAndExternal'),
                            $profile);
    }
}

class RawPublicAndExternalNoticeStream extends NoticeStream
{
    function getNoticeIds($offset, $limit, $since_id, $max_id)
    {

        $notice = new Notice();

        $notice->selectAdd();
        $notice->selectAdd('id');

        $notice->orderBy('id DESC');

        if (!is_null($offset)) {
            $notice->limit($offset, $limit);
        }

		$notice->whereAdd('is_local !='. Notice::LOCAL_NONPUBLIC);
		$notice->whereAdd('is_local !='. Notice::GATEWAY);
		$notice->whereAdd('repeat_of IS NULL');

        // don't show sandboxed users in public timelines, unless you are a mod
        $hide_sandboxed = true;
        $cur_profile = Profile::current();
        if($cur_profile instanceof Profile) {
        	if($cur_profile->hasRight(Right::REVIEWSPAM)) {
        		$hide_sandboxed = false;
        	}
        }
        if($hide_sandboxed) {
        	$notice->whereAdd('profile_id NOT IN (SELECT profile_id FROM profile_role WHERE role =\''.Profile_role::SANDBOXED.'\')');
        }

        if(!empty($max_id) && is_numeric($max_id)) {
            $notice->whereAdd('id < '.$max_id);
        }

        if(!empty($since_id) && is_numeric($since_id)) {
            $notice->whereAdd('id > '.$since_id);
        }

        $ids = array();

        if ($notice->find()) {
            while ($notice->fetch()) {
                $ids[] = $notice->id;
            }
        }

        $notice->free();
        $notice = NULL;

        return $ids;
    }
}


code:
<?php

  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   ·                                                                            ·
   ·  Extends GNU social's Profile_block class with useful functions            ·
   ·                                                                            ·
   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  ·                                                                             ·
  ·                                                                             ·
  ·                             Q V I T T E R                                   ·
  ·                                                                             ·
  ·                      https://git.gnu.io/h2p/Qvitter                         ·
  ·                                                                             ·
  ·                                                                             ·
  ·                                 <o)                                         ·
  ·                                  /_////                                     ·
  ·                                 (____/                                      ·
  ·                                          (o<                                ·
  ·                                   o> \\\\_\                                 ·
  ·                                 \\)   \____)                                ·
  ·                                                                             ·
  ·                                                                             ·
  ·                                                                             ·
  ·  Qvitter 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 three of the License or (at  ·
  ·  your option) any later version.                                            ·
  ·                                                                             ·
  ·  Qvitter is distributed  in hope that  it will be  useful but  WITHOUT ANY  ·
  ·  WARRANTY;  without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>.            ·
  ·                                                                             ·
  ·  Contact h@nnesmannerhe.im if you have any questions.                       ·
  ·                                                                             ·
  · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */

if (!defined('GNUSOCIAL')) { exit(1); }

class QvitterBlocked extends Profile_block
{

    const CACHE_WINDOW = 201;

    public static function getBlocked($profile_id, $offset = 0, $limit = PROFILES_PER_PAGE)
    {
        $ids = self::getBlockedIDs($profile_id, $offset, $limit);
        try {
        $blocked = Profile_block::listFind('blocked', $ids);
            return $blocked;
        } catch(NoResultException $e) {
            return false;
        }
    }

    public static function getBlockedIDs($profile_id, $offset, $limit)
    {
        $cacheKey = 'qvitterblocked:'.$profile_id;

        $queryoffset = $offset;
        $querylimit = $limit;

        if ($offset + $limit <= self::CACHE_WINDOW) {
            // Oh, it seems it should be cached
            $ids = self::cacheGet($cacheKey);
            if (is_array($ids)) {
                return array_slice($ids, $offset, $limit);
            }
            // Being here indicates we didn't find anything cached
            // so we'll have to fill it up simultaneously
            $queryoffset = 0;
            $querylimit  = self::CACHE_WINDOW;
        }

        $blocks = new Profile_block();
        $blocks->blocker = $profile_id;
        $blocks->selectAdd('blocked');
        $blocks->whereAdd("blocked != {$profile_id}");
        $blocks->orderBy('modified DESC');
        $blocks->limit($queryoffset, $querylimit);

        if (!$blocks->find()) {
            return array();
        }

        $ids = $blocks->fetchAll('blocked');

        // If we're simultaneously filling up cache, remember to slice
        if ($queryoffset === 0 && $querylimit === self::CACHE_WINDOW) {
            self::cacheSet($cacheKey, $ids);
            return array_slice($ids, $offset, $limit);
        }

        return $ids;
    }

    /**
     * Flush cached blocks when blocks are updated
     *
     * @param mixed $dataObject Original version of object
     *
     * @return boolean success flag.
     */
    function update($dataObject=false)
    {
        self::blow('qvitterblocked:'.$this->blocker);
        self::blow('qvitterblocked:'.$this->blocked);

        return parent::update($dataObject);
    }

}


code:
<?php

  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   ·                                                                            ·
   ·  Get muted profiles for a profile                                          ·
   ·                                                                            ·
   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  ·                                                                             ·
  ·                                                                             ·
  ·                             Q V I T T E R                                   ·
  ·                                                                             ·
  ·                      https://git.gnu.io/h2p/Qvitter                         ·
  ·                                                                             ·
  ·                                                                             ·
  ·                                 <o)                                         ·
  ·                                  /_////                                     ·
  ·                                 (____/                                      ·
  ·                                          (o<                                ·
  ·                                   o> \\\\_\                                 ·
  ·                                 \\)   \____)                                ·
  ·                                                                             ·
  ·                                                                             ·
  ·                                                                             ·
  ·  Qvitter 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 three of the License or (at  ·
  ·  your option) any later version.                                            ·
  ·                                                                             ·
  ·  Qvitter is distributed  in hope that  it will be  useful but  WITHOUT ANY  ·
  ·  WARRANTY;  without even the implied warranty of MERCHANTABILTY 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 Qvitter. If not, see <http://www.gnu.org/licenses/>.            ·
  ·                                                                             ·
  ·  Contact h@nnesmannerhe.im if you have any questions.                       ·
  ·                                                                             ·
  · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */

if (!defined('GNUSOCIAL')) { exit(1); }

class QvitterMuted
{

    public static function getMutedProfiles($profile_id, $offset = 0, $limit = PROFILES_PER_PAGE)
    {

        $ids = self::getMutedIDs($profile_id, $offset, $limit);

        if(count($ids) === 0) {
            return false;
        } else {
            $profiles = array();
            foreach($ids as $id) {
                try {
                    $profiles[] = Profile::getByID($id);
                } catch (Exception $e) {
                    //
                }
            }
            if(count($profiles) === 0) {
                return false;
            } else {
                return $profiles;
            }
        }
    }

    public static function getMutedIDs($profile_id, $offset, $limit)
    {

        if(!is_numeric($profile_id)) {
            return false;
        }

        $mutes = new Profile_prefs();
        $mutes->selectAdd('topic');
        $mutes->whereAdd("profile_id = ".$profile_id);
        $mutes->whereAdd("namespace = 'qvitter'");
        $mutes->whereAdd("data = '1'");
        $mutes->whereAdd("topic LIKE 'mute:%'");
        $mutes->orderBy('modified DESC');
        $mutes->limit($offset, $limit);

        if (!$mutes->find()) {
            return array();
        }

        $topics = $mutes->fetchAll('topic');
        $ids = array();
        foreach($topics as $topic) {
            $topic_exploded = explode(':',$topic);
            if(is_numeric($topic_exploded[1])) {
                $ids[] = $topic_exploded[1];
            }
        }

        return $ids;
    }

}


code:
<?php
/**
 * Table Definition for qvitternotification
 */

class QvitterNotification extends Managed_DataObject
{
    public $__table = 'qvitternotification';  // table name
    public $id;                              // int(4)  primary_key not_null
    public $to_profile_id;                   // int(4)
    public $from_profile_id;                 // int(4)
    public $ntype;                           // varchar(7)
    public $notice_id;                       // int(4)
    public $is_seen;                         // int(tiny)
    public $created;                         // datetime  multiple_key not_null

    public static function schemaDef()
    {
        return array(
            'fields' => array(
                'id' => array('type' => 'serial', 'not null' => true),
                'to_profile_id' => array('type' => 'int', 'not null'=>true, 'description' => 'the profile being notified'),
                'from_profile_id' => array('type' => 'int', 'not null'=>true, 'description' => 'the profile that is notifying'),
                'ntype' => array('type' => 'varchar', 'length' => 7, 'description' => 'reply, like, mention or follow'),
                'notice_id' => array('type' => 'int', 'description' => 'id for the reply or mention or notice being faved'),
                'is_seen' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'if the notification has been seen'),
                'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created')
            ),
            'primary key' => array('id'),
            'foreign keys' => array(
                'qvitternotification_to_profile_id_fkey' => array('profile', array('to_profile_id' => 'id')),
                'qvitternotification_from_profile_id_fkey' => array('profile', array('from_profile_id' => 'id')),
                // removing this because there can be rows without related notice_id
                //'qvitternotification_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
            ),
            'indexes' => array(
                'qvitternotification_created_idx' => array('created'),
                'qvitternotification_to_profile_id_idx' => array('to_profile_id'),
                'qvitternotification_from_profile_id_idx' => array('from_profile_id'),
            ),
        );
    }

    /**
     * Wrapper for record insertion to update related caches
     */
    function insert()
    {
        $result = parent::insert();

        if ($result) {
            self::blow('qvitternotification:stream:%d', $this->to_profile_id);
        }

        return $result;
    }

    static public function beforeSchemaUpdate()
    {
        $table = strtolower(get_called_class());
        $schema = Schema::get();
        try {
            $schemadef = $schema->getTableDef($table);
        } catch (SchemaTableMissingException $e) {
            printfnq("\nTable '$table' not created yet, so nothing to do with it before Schema Update... DONE.");
            return;
        }

        printfnq("\nEnsuring no NULL values for foreign keys in QvitterNotification...");
        // Because constraints to profile and notice table assume not null, we must
        // remove any values in these columns that are NULL (or 0), because they
        // are invalid anyway.
        $qn = new QvitterNotification();
        foreach (['to_profile_id', 'from_profile_id'] as $field) {
            $qn->whereAdd(sprintf('%s is NULL', $field), 'OR');
            $qn->whereAdd(sprintf('%s = 0', $field), 'OR');
        }
        if ($qn->find()) {
            printfnq(" removing {$qn->N} rows...");
            while ($qn->fetch()) {
                $qn->delete();
            }
        }
        printfnq("DONE.\n");

        printfnq("Ensuring no dead profile or notice IDs are stored in QvitterNotification...");
        // We could probably build a single statement for this but I just want it done...
        // or maybe be smart and take it directly from our defined 'foreign keys'... but oh well!
        $constraints = ['to_profile_id'     => 'profile:id',
                        'from_profile_id'   => 'profile:id'];
        foreach ($constraints as $field=>$foreign) {
            $qn = new QvitterNotification();
            $qn->selectAdd();
            $qn->selectAdd('qvitternotification.id');   // to avoid confusion with profile.id, also we only need the primary key
            $qn->joinAdd([$field, $foreign], 'LEFT');
            $qn->whereAdd(str_replace(':', '.', $foreign).' IS NULL');
            if ($qn->find()) {
                printfnq("\n{$field}: {$qn->N} rows...");
                while ($qn->fetch()) {
                    $qn->delete();
                }
            }
        }
        printfnq("DONE.\n");
    }
}


code:
.minicolors {
	position: relative;
}

.minicolors-swatch {
	position: absolute;
	vertical-align: middle;
	background: url(../img/jquery.minicolors.png) -80px 0;
	border: solid 1px #ccc;
	cursor: text;
	padding: 0;
	margin: 0;
	display: inline-block;
}

.minicolors-swatch-color {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
}

.minicolors input[type=hidden] + .minicolors-swatch {
	width: 28px;
	position: static;
	cursor: pointer;
}

/* Panel */
.minicolors-panel {
	position: absolute;
	width: 173px;
	height: 152px;
	background: white;
	border: solid 1px #CCC;
	box-shadow: 0 0 20px rgba(0, 0, 0, .2);
	z-index: 99999;
	-moz-box-sizing: content-box;
	-webkit-box-sizing: content-box;
	box-sizing: content-box;
	display: none;
}

.minicolors-panel.minicolors-visible {
	display: block;
}

/* Panel positioning */
.minicolors-position-top .minicolors-panel {
	top: -154px;
}

.minicolors-position-right .minicolors-panel {
	right: 0;
}

.minicolors-position-bottom .minicolors-panel {
	top: auto;
}

.minicolors-position-left .minicolors-panel {
	left: 0;
}

.minicolors-with-opacity .minicolors-panel {
	width: 194px;
}

.minicolors .minicolors-grid {
	position: absolute;
	top: 1px;
	left: 1px;
	width: 150px;
	height: 150px;
	background: url(../img/jquery.minicolors.png) -120px 0;
	cursor: crosshair;
}

.minicolors .minicolors-grid-inner {
	position: absolute;
	top: 0;
	left: 0;
	width: 150px;
	height: 150px;
	background: none;
}

.minicolors-slider-saturation .minicolors-grid {
	background-position: -420px 0;
}

.minicolors-slider-saturation .minicolors-grid-inner {
	background: url(../img/jquery.minicolors.png) -270px 0;
}

.minicolors-slider-brightness .minicolors-grid {
	background-position: -570px 0;
}

.minicolors-slider-brightness .minicolors-grid-inner {
	background: black;
}

.minicolors-slider-wheel .minicolors-grid {
	background-position: -720px 0;
}

.minicolors-slider,
.minicolors-opacity-slider {
	position: absolute;
	top: 1px;
	left: 152px;
	width: 20px;
	height: 150px;
	background: white url(../img/jquery.minicolors.png) 0 0;
	cursor: row-resize;
}

.minicolors-slider-saturation .minicolors-slider {
	background-position: -60px 0;
}

.minicolors-slider-brightness .minicolors-slider {
	background-position: -20px 0;
}

.minicolors-slider-wheel .minicolors-slider {
	background-position: -20px 0;
}

.minicolors-opacity-slider {
	left: 173px;
	background-position: -40px 0;
	display: none;
}

.minicolors-with-opacity .minicolors-opacity-slider {
	display: block;
}

/* Pickers */
.minicolors-grid .minicolors-picker {
	position: absolute;
	top: 70px;
	left: 70px;
	width: 12px;
	height: 12px;
	border: solid 1px black;
	border-radius: 10px;
	margin-top: -6px;
	margin-left: -6px;
	background: none;
}

.minicolors-grid .minicolors-picker > div {
	position: absolute;
	top: 0;
	left: 0;
	width: 8px;
	height: 8px;
	border-radius: 8px;
	border: solid 2px white;
	-moz-box-sizing: content-box;
	-webkit-box-sizing: content-box;
	box-sizing: content-box;
}

.minicolors-picker {
	position: absolute;
	top: 0;
	left: 0;
	width: 18px;
	height: 2px;
	background: white;
	border: solid 1px black;
	margin-top: -2px;
	-moz-box-sizing: content-box;
	-webkit-box-sizing: content-box;
	box-sizing: content-box;
}

/* Inline controls */
.minicolors-inline {
	display: inline-block;
}

.minicolors-inline .minicolors-input {
	display: none !important;
}

.minicolors-inline .minicolors-panel {
	position: relative;
	top: auto;
	left: auto;
	box-shadow: none;
	z-index: auto;
	display: inline-block;
}

/* Default theme */
.minicolors-theme-default .minicolors-swatch {
	top: 5px;
	left: 5px;
	width: 18px;
	height: 18px;
}
.minicolors-theme-default.minicolors-position-right .minicolors-swatch {
	left: auto;
	right: 5px;
}
.minicolors-theme-default.minicolors {
	width: auto;
	display: inline-block;
}
.minicolors-theme-default .minicolors-input {
	height: 20px;
	width: auto;
	display: inline-block;
	padding-left: 26px;
}
.minicolors-theme-default.minicolors-position-right .minicolors-input {
	padding-right: 26px;
	padding-left: inherit;
}

/* Bootstrap theme */
.minicolors-theme-bootstrap .minicolors-swatch {
	top: 3px;
	left: 3px;
	width: 28px;
	height: 28px;
	border-radius: 3px;
}
.minicolors-theme-bootstrap.minicolors-position-right .minicolors-swatch {
	left: auto;
	right: 3px;
}
.minicolors-theme-bootstrap .minicolors-input {
	padding-left: 44px;
}
.minicolors-theme-bootstrap.minicolors-position-right .minicolors-input {
	padding-right: 44px;
	padding-left: 12px;
}