if (IN_serendipity !== true) { die ("Don't hack!"); } @serendipity_plugin_api::load_language(dirname(__FILE__)); include_once dirname(__FILE__) . '/plugin_version.inc.php'; require_once dirname(__FILE__) . '/classes/Twitter.php'; require_once dirname(__FILE__) . '/classes/TwitterOAuthApi.php'; require_once dirname(__FILE__) . '/classes/RedirectCheck.php'; require_once dirname(__FILE__) . '/classes/UrlShortener.php'; require_once dirname(__FILE__) . '/classes/TwitterPluginDbAccess.php'; require_once dirname(__FILE__) . '/classes/TwitterPluginFileAccess.php'; require_once dirname(__FILE__) . '/classes/twitter_entry_defs.include.php'; // writes a debug log into templates_c @define('PLUGIN_TWITTER_DEBUG', FALSE); // Consumer settings for the S9Y webapp @define('PLUGIN_TWITTER_OAUTH_TWITTER_CONSUMERKEY', 'ScXsM6UiDU1nDl8u6tacrw'); @define('PLUGIN_TWITTER_OAUTH_TWITTER_CONSUMERSECRET', '8zR0TKHKNN6gTq8iGP12zRz5P39OPB1nLbLTkHY'); class serendipity_event_twitter extends serendipity_plugin { var $supported_services = array( 'raw' => "uncompressed", '7ax.de' => "7ax.de", 'bitly' => "bit.ly", 'piratly' => "pirat.ly", 'yourls' => "yourls", 'jmp' => "j.mp", 'tinyurl' => "tinyurl.com", 'isgd' => "is.gd", 'twurl' => "twurl.nl", 'delivr' => "delivr.com", 'linktrimmer' => 'Linktrimmer Plugin', ); function introspect(&$propbag) { global $serendipity; $propbag->add('name', PLUGIN_EVENT_TWITTER_NAME); $propbag->add('description', PLUGIN_EVENT_TWITTER_DESC); $propbag->add('stackable', false); $propbag->add('author', 'Grischa Brockhaus, Peter Heimann'); $propbag->add('requirements', array( 'serendipity' => '0.7', 'smarty' => '2.6.7', 'php' => '5.1.0' )); $propbag->add('version', PLUGIN_TWITTER_VERSION); $propbag->add('groups', array('FRONTEND_VIEWS')); $propbag->add('event_hooks', array( 'entry_display' => true, 'external_plugin' => true, 'backend_header' => true, 'backend_display' => true, // Extended attributes 'backend_publish' => true, // An entry was puplished (was draft before or saved from the scratch). 'backend_frontpage_display' => true, 'backend_sidebar_entries' => true, 'backend_sidebar_admin_appearance' => true, 'backend_sidebar_entries_event_display_tweeter' => true, 'backend_delete_entry' => true, 'css' => true, 'frontend_footer' => true, 'frontend_saveComment' => true, // Set moderation if needed. )); $propbag->add('legal', array( 'services' => array( 'twitter.com' => array( 'url' => 'https://www.twitter.com', 'desc' => 'Transmits data to and from twitter' ), 'bit.ly' => array( 'url' => 'https://www.bit.ly', 'desc' => 'Transmits data to and from bit.ly for URL shortening' ), 'yourls' => array( 'url' => 'https://www.yourls.org', 'desc' => 'Transmits data to and from yourls.org for URL shortening' ), 'piratly' => array( 'url' => 'https://www.pirat.ly', 'desc' => 'Transmits data to and from pirat.ly for URL shortening' ), ), 'frontend' => array( 'Depending on the configuration, can embed JavaScript from twitter.com, which transmits the IP and visitor metadata to twitter.', ), 'backend' => array( 'Can send entry data to twitter.com, can embed tweets in the backend and frontend' ), 'cookies' => array( ), 'stores_user_input' => false, 'stores_ip' => false, 'uses_ip' => false, 'transmits_user_input' => true )); $configuration = array(); if (class_exists('serendipity_event_twittertweeter')) { $configuration[] = "tweeter_warning"; } $configuration[] = "config_tab"; $config_announce = array( 'announce_articles_title', 'announce_articles', 'announce_via_accounts', 'announce_format', 'announce_with_tags', 'anounce_url_service', 'announce_articles_default_no', 'announce_bitly_description', 'announce_bitly_login','announce_bitly_apikey','announce_piratly_description', 'announce_piratly_apikey', 'announce_yourls_description', 'announce_yourls_url', 'announce_yourls_apikey' ); $config_twitter = array( 'twitter_title', 'id_count', 'id_title', 'id_service', 'twittername', 'twitterpwd','twitteroa_sign_in','twitteroa_consumer_key','twitteroa_consumer_secret' ); if (is_numeric($this->get_config('id_count',1))) { $idcount = $this->get_config('id_count',1); } else { $idcount = 1; } for ($idx=2; $idx<=$idcount; $idx++) { $config_twitter[] = 'id_title' . $idx; $config_twitter[] = 'id_service' . $idx; $config_twitter[] = 'twittername' . $idx; $config_twitter[] = 'twitterpwd' . $idx; $config_twitter[] = 'twitteroa_sign_in' . $idx; } $config_tweeter = array( 'tweeter_title', 'tweeter_show', 'tweeter_history', 'tweeter_history_count', 'tweeter_timeline' ); $config_tweetback = array( 'tweetback_title', 'do_tweetbacks', 'twitter_api', 'twitter_generic_acc', 'tweetback_type', 'tweetback_moderate', 'ignore_tweetbacks_by_name', 'tweetback_url', 'tweetback_check_freq' ); $config_tweetthis = array( 'tweetthis_title', 'do_tweetthis', 'do_identicathis', 'tweetthis_format', 'tweetthis_button', 'tweetthis_newwindow', 'tweetthis_smartify', 'show_shorturl' ); $config_general = array( 'general_title', 'plugin_rel_url', 'general_oa_consumerdesc', 'general_oa_consumerkey', 'general_oa_consumersecret' ); switch ($_GET['plugintab'] ?? '') { case 'announce': $configuration = array_merge($configuration, $config_announce ); break; case 'tweeter': $configuration = array_merge($configuration, $config_tweeter ); break; case 'tweetback': $configuration = array_merge($configuration, $config_tweetback ); break; case 'tweetthis': $configuration = array_merge($configuration, $config_tweetthis ); break; case 'global': $configuration = array_merge($configuration, $config_general ); break; case 'all': $configuration = array_merge($configuration, $config_twitter, $config_tweeter, $config_announce, $config_tweetback, $config_general ); break; case 'identities': default: $configuration = array_merge($configuration, $config_twitter ); } $propbag->add('configuration', $configuration); } function handleConfig($name, &$propbag, $idx = '') { global $serendipity; switch($name) { case 'twitteroa_consumer_secret': if (!$this->get_config('id_service' . $idx) OR $this->get_config('id_service' . $idx) == "twitter") { $u = $this->get_config('twittername' . $idx); $kd = $this->get_config('twitteroa_key_' . $idx . $u); $td = $this->get_config('twitteroa_token_' . $idx . $u); if (!empty($kd) && !empty($td)) { // OAuth token and key is setup. } else { $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_CONSUMER_SECRET); $propbag->add('description', PLUGIN_EVENT_TWITTER_CONSUMER_KEY_DESC); } } break; case 'twitteroa_consumer_key': if (!$this->get_config('id_service' . $idx) OR $this->get_config('id_service' . $idx) == "twitter") { $u = $this->get_config('twittername' . $idx); $kd = $this->get_config('twitteroa_key_' . $idx . $u); $td = $this->get_config('twitteroa_token_' . $idx . $u); if (!empty($kd) && !empty($td)) { // OAuth token and key is setup. } else { $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_CONSUMER_KEY); $propbag->add('description', PLUGIN_EVENT_TWITTER_CONSUMER_KEY_DESC); } } break; case 'twitteroa_sign_in': if (!$this->get_config('id_service' . $idx) OR $this->get_config('id_service' . $idx) == "twitter") { $u = $this->get_config('twittername' . $idx); $kd = $this->get_config('twitteroa_key_' . $idx . $u); $td = $this->get_config('twitteroa_token_' . $idx . $u); $csecret = $this->get_config('twitteroa_consumer_secret' . $idx); $ckey = $this->get_config('twitteroa_consumer_key' . $idx); // Use s9y consumer stuff, if old plugin versions did not set this up already if (empty($ckey) || empty($csecret)) { $consumer = $this->twitteroa_global_consumersettings(); $csecret = $consumer['secret']; $ckey = $consumer['key']; $this->set_config('twitteroa_consumer_secret' . $idx, $csecret); $this->set_config('twitteroa_consumer_key' . $idx, $ckey); } if (!empty($kd) && !empty($td)) { // OAuth token and key is setup: Delete connection $linkdel = $serendipity['baseURL'] . $serendipity['indexFile'] . '?/' . TwitterPluginFileAccess::get_permaplugin_path() . '/twitteroa-del=' . $idx; $propbag->add('type', 'content'); $propbag->add('default', PLUGIN_EVENT_TWITTER_VERBINDUNG_OK . ' '.PLUGIN_EVENT_TWITTER_VERBINDUNG_DEL.''); } else { // OAuth not yet setup, but we have consumer key/secret: Login and connect application $url = $serendipity['baseURL'] . $serendipity['indexFile'] . '?/' . TwitterPluginFileAccess::get_permaplugin_path() . '/twitteroa-redirect=' . $idx; $propbag->add('type', 'content'); $propbag->add('default', PLUGIN_EVENT_TWITTER_SIGN_IN.'

' . PLUGIN_EVENT_TWITTER_SIGNIN . '

'); } } break; } return true; } function introspect_config_item($name, &$propbag) { global $serendipity; $tb_use_url = array( 'status' => PLUGIN_EVENT_TWITTER_TB_USE_URL_STATUS, 'profile' => PLUGIN_EVENT_TWITTER_TB_USE_URL_PROFILE, 'weburl' => PLUGIN_EVENT_TWITTER_TB_USE_URL_WEBURL ); $id_services = array( 'twitter' => PLUGIN_EVENT_TWITTER_ACCOUNT_SERVICE_TWITTER, 'identica' => PLUGIN_EVENT_TWITTER_ACCOUNT_SERVICE_IDENTICA, ); // Get actual idetntifier count if (is_numeric($this->get_config('id_count',1))) { $identitycount = $this->get_config('id_count',1); } else { $identitycount = 1; } switch($name) { case 'tweeter_warning': $propbag->add('type', 'content'); $propbag->add('default', PLUGIN_EVENT_TWITTER_TWEETER_WARNING); break; case 'config_tab': $config_tabs = array( 'identities' => PLUGIN_EVENT_TWITTER_CFGTAB_IDENTITIES, 'tweetback' => PLUGIN_EVENT_TWITTER_CFGTAB_TWEETBACK, 'announce' => PLUGIN_EVENT_TWITTER_CFGTAB_ANNOUNCE, 'tweeter' => PLUGIN_EVENT_TWITTER_CFGTAB_TWEETER, 'tweetthis' => PLUGIN_EVENT_TWITTER_CFGTAB_TWEETTHIS, 'global' => PLUGIN_EVENT_TWITTER_CFGTAB_GLOBAL, 'all' => PLUGIN_EVENT_TWITTER_CFGTAB_ALL, ); $actConfigUrl = $this->curPageURL(); $querypar = "plugintab"; $htmltabline = PLUGIN_EVENT_TWITTER_CFGTAB ; foreach ($config_tabs as $tabkey => $tabvalue) { $tablink = $actConfigUrl; if (strpos($actConfigUrl, "&$querypar=") === FALSE) { $tablink = $actConfigUrl . "&$querypar=$tabkey"; } else { $tablink = preg_replace('@' . $querypar . '=.*@',"$querypar=$tabkey",$actConfigUrl); } $htmltabline .= ' ['. $tabvalue .'] '; } $propbag->add('type', 'content'); $propbag->add('default', $htmltabline); break; // Identities case 'twitter_title': $propbag->add('type', 'content'); $propbag->add('default', '

' . PLUGIN_EVENT_TWITTER_IDENTITIES . '

'); break; case 'id_count': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ACCOUNT_IDCOUNT); $propbag->add('description', PLUGIN_EVENT_TWITTER_ACCOUNT_IDCOUNT_DESC); $propbag->add('default', 1); break; case 'id_title': $propbag->add('type', 'content'); $propbag->add('default', '

' . PLUGIN_EVENT_TWITTER_IDENTITY . ' (1)

'); break; case 'id_service': $propbag->add('type', 'select'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ACCOUNT_SERVICE); $propbag->add('description', PLUGIN_EVENT_TWITTER_ACCOUNT_SERVICE_DESC); $propbag->add('select_values', $id_services); $propbag->add('default', 'twitter'); break; case 'twittername': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ACCOUNT_NAME); $propbag->add('description', PLUGIN_EVENT_TWITTER_ACCOUNT_NAME_DESC); break; case 'twitterpwd': if (!$this->get_config('id_service') OR $this->get_config('id_service') == "identica") { $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ACCOUNT_PWD); $propbag->add('description', PLUGIN_EVENT_TWITTER_ACCOUNT_PWD_DESC); $propbag->add('input_type', 'password'); } break; case 'twitteroa_consumer_key': $this->handleConfig('twitteroa_consumer_key', $propbag); break; case 'twitteroa_consumer_secret': $this->handleConfig('twitteroa_consumer_secret', $propbag); break; case 'twitteroa_sign_in': $this->handleConfig('twitteroa_sign_in', $propbag); break; // Backend Client case 'tweeter_title': $propbag->add('type', 'content'); $propbag->add('default', '

' . PLUGIN_EVENT_TWITTER_TWEETER_TITLE . '

'); break; case 'tweeter_show': $tweetershow = array( 'frontpage' => PLUGIN_EVENT_TWITTER_TWEETER_SHOW_FRONTPAGE, 'sidebar' => PLUGIN_EVENT_TWITTER_TWEETER_SHOW_SIDEBAR, 'disable' => PLUGIN_EVENT_TWITTER_TWEETER_SHOW_DISABLE ); $propbag->add('type', 'select'); $propbag->add('name', PLUGIN_EVENT_TWITTER_TWEETER_SHOW); $propbag->add('description', PLUGIN_EVENT_TWITTER_TWEETER_SHOW_DESC); $propbag->add('select_values', $tweetershow); $propbag->add('default', 'disable'); break; case 'tweeter_timeline': $tb_statuses = array( 'public_timeline' => 'public_timeline', 'home_timeline' => 'home_timeline', 'friends_timeline' => 'friends_timeline', 'user_timeline' => 'user_timeline', 'mentions' => 'mentions', 'retweeted_by_me' => 'retweeted_by_me', 'retweeted_to_me' => 'retweeted_to_me', 'retweets_of_me' => 'retweets_of_me', ); $propbag->add('type', 'select'); $propbag->add('name', PLUGIN_EVENT_TWITTER_TIMELINE); $propbag->add('description', PLUGIN_EVENT_TWITTER_TIMELINE_DESC); $propbag->add('select_values', $tb_statuses); $propbag->add('default', 'home_timeline'); break; case 'tweeter_history': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_TWITTER_TWEETER_HISTORY); $propbag->add('description', PLUGIN_EVENT_TWITTER_TWEETER_HISTORY_DESC); $propbag->add('default', false); break; case 'tweeter_history_count': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_TWEETER_HISTORY_COUNT); $propbag->add('description', PLUGIN_EVENT_TWITTER_TWEETER_HISTORY_COUNT_DESC); $propbag->add('default', '10'); break; // Article announcement case 'announce_articles_title': $propbag->add('type', 'content'); $propbag->add('default', '

' . PLUGIN_EVENT_TWITTER_ANNOUNCE_ARTICLES_TITLE . '

'); break; case 'announce_articles': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ANNOUNCE_ARTICLES); $propbag->add('description', PLUGIN_EVENT_TWITTER_ANNOUNCE_ARTICLES_DESC); $propbag->add('default', false); break; case 'announce_articles_default_no': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ANNOUNCE_ARTICLES_NO); $propbag->add('description', PLUGIN_EVENT_TWITTER_ANNOUNCE_ARTICLES_NO_DESC); $propbag->add('default', false); break; case 'announce_via_accounts': $propbag->add('type', 'multiselect'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ANNOUNCE_ACCOUNTS); $propbag->add('description', PLUGIN_EVENT_TWITTER_ANNOUNCE_ACCOUNTS_DESC); $propbag->add('select_values', $this->load_identities()); $propbag->add('default', '0'); break; case 'announce_format': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ANNOUNCE_FORMAT); $propbag->add('description', PLUGIN_EVENT_TWITTER_ANNOUNCE_FORMAT_DESC); $propbag->add('default', $this->get_default_announceformat()); break; case 'announce_with_tags': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ANNOUNCE_WITHTTAGS); $propbag->add('description', PLUGIN_EVENT_TWITTER_ANNOUNCE_WITHTTAGS_DESC); $propbag->add('default', false); break; case 'anounce_url_service': $propbag->add('type', 'select'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ANNOUNCE_SERVICE); $propbag->add('description', PLUGIN_EVENT_TWITTER_ANNOUNCE_SERVICE_DESC); $propbag->add('select_values', $this->supported_services); $propbag->add('default', '7ax.de'); break; case 'announce_bitly_description': $propbag->add('type', 'content'); $propbag->add('default', PLUGIN_EVENT_TWITTER_ANNOUNCE_BITLYDESC); break; case 'announce_bitly_login': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ANNOUNCE_BITLYLOGIN); $propbag->add('default', 'bitlyapidemo'); break; case 'announce_bitly_apikey': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ANNOUNCE_BITLYAPIKEY); $propbag->add('default', 'R_0da49e0a9118ff35f52f629d2d71bf07'); break; case 'announce_piratly_description': $propbag->add('type', 'content'); $propbag->add('default', PLUGIN_EVENT_TWITTER_ANNOUNCE_PIRATLYDESC); break; case 'announce_piratly_apikey': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ANNOUNCE_PIRATLYAPIKEY); $propbag->add('default', '0'); break; case 'announce_yourls_description': $propbag->add('type', 'content'); $propbag->add('default', PLUGIN_EVENT_TWITTER_ANNOUNCE_YOURLSDESC); break; case 'announce_yourls_url': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ANNOUNCE_YOURLSURL); $propbag->add('default', 'http://www.yourls.org'); break; case 'announce_yourls_apikey': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ANNOUNCE_YOURLSAPIKEY); $propbag->add('default', 'API key'); break; // Tweetbacks case 'twitter_api' : $apis = array( 'api10' => PLUGIN_EVENT_TWITTER_API_10, 'api11' => PLUGIN_EVENT_TWITTER_API_11, ); $propbag->add('type', 'select'); $propbag->add('name', PLUGIN_EVENT_TWITTER_API_TYPE); $propbag->add('description', PLUGIN_EVENT_TWITTER_API_TYPE_DESC); $propbag->add('select_values', $apis); $propbag->add('default', 'api10'); break; case 'twitter_generic_acc': $propbag->add('name', PLUGIN_TWITTER_OAUTHACC); $propbag->add('description', PLUGIN_TWITTER_OAUTHACC_DESC); $propbag->add('type', 'select'); $propbag->add('select_values', serendipity_event_twitter::getTwitterOauths()); $propbag->add('default', '1'); break; case 'tweetback_title': $propbag->add('type', 'content'); $propbag->add('default', '

' . PLUGIN_EVENT_TWITTER_TWEETBACKS_TITLE . '

'); break; case 'do_tweetbacks': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_TWITTER_DO_TWEETBACKS); $propbag->add('description', PLUGIN_EVENT_TWITTER_DO_TWEETBACKS_DESC); $propbag->add('default', false); break; case 'tweetback_type': $tb_types = array( 'TRACKBACK' => PLUGIN_EVENT_TWITTER_TB_TYPE_TRACKBACK, 'NORMAL' => PLUGIN_EVENT_TWITTER_TB_TYPE_COMMENT, ); $propbag->add('type', 'select'); $propbag->add('name', PLUGIN_EVENT_TWITTER_TB_TYPE); $propbag->add('description', PLUGIN_EVENT_TWITTER_TB_TYPE_DESC); $propbag->add('select_values', $tb_types); $propbag->add('default', 'TRACKBACK'); break; case 'tweetback_moderate': $tb_types = array( 'save' => PLUGIN_EVENT_TWITTER_TB_MODERATE_DEFAULT, 'pending' => REQUIRES_REVIEW, //'confirm' => REQUIRES_REVIEW, 'approved' => APPROVE_COMMENT, ); $propbag->add('type', 'select'); $propbag->add('name', PLUGIN_EVENT_TWITTER_TB_MODERATE); $propbag->add('description', PLUGIN_EVENT_TWITTER_TB_MODERATE_DESC); $propbag->add('select_values', $tb_types); $propbag->add('default', 'approved'); break; case 'ignore_tweetbacks_by_name': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_IGNORE_TWEETBACKS_BYNAME); $propbag->add('description', PLUGIN_EVENT_TWITTER_IGNORE_TWEETBACKS_BYNAME_DESC); $propbag->add('default', $this->get_config('twittername')); break; case 'tweetback_url': $propbag->add('type', 'select'); $propbag->add('name', PLUGIN_EVENT_TWITTER_TB_USE_URL); $propbag->add('description', PLUGIN_EVENT_TWITTER_TB_USE_URL_DESC); $propbag->add('select_values', $tb_use_url); $propbag->add('default', 'status'); break; case 'tweetback_check_freq': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_TWEETBACK_CHECK_FREQ); $propbag->add('description', PLUGIN_EVENT_TWITTER_TWEETBACK_CHECK_FREQ_DESC); $propbag->add('default', '30'); break; // Tweet this case 'tweetthis_title': $propbag->add('type', 'content'); $propbag->add('default', '

' . PLUGIN_EVENT_TWITTER_TWEETTHIS_TITLE . '

'); break; case 'do_tweetthis': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_TWITTER_DO_TWEETTHIS); $propbag->add('description', PLUGIN_EVENT_TWITTER_DO_TWEETTHIS_DESC); $propbag->add('default', false); break; case 'do_identicathis': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_TWITTER_DO_IDENTICATHIS); $propbag->add('description', PLUGIN_EVENT_TWITTER_DO_IDENTICATHIS_DESC); $propbag->add('default', false); break; case 'tweetthis_format': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_TWEETTHIS_FORMAT); $propbag->add('description', PLUGIN_EVENT_TWITTER_TWEETTHIS_FORMAT_DESC); $propbag->add('default', '#title# #link#'); break; case 'tweetthis_button': $propbag->add('type', 'radio'); $propbag->add('name', PLUGIN_EVENT_TWITTER_TWEETTHIS_FORMAT_BUTTON); $propbag->add('description', PLUGIN_EVENT_TWITTER_TWEETTHIS_FORMAT_BUTTON_DESC); $propbag->add('radio', array( 'value' => array('black', 'white'), 'desc' => array(PLUGIN_EVENT_TWITTER_TWEETTHIS_FORMAT_BUTTON_BLACK, PLUGIN_EVENT_TWITTER_TWEETTHIS_FORMAT_BUTTON_WHITE) )); $propbag->add('default', 'black'); break; case 'tweetthis_newwindow': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_TWITTER_TWEETTHIS_NEWWINDOW); $propbag->add('description', PLUGIN_EVENT_TWITTER_TWEETTHIS_NEWWINDOW_DESC); $propbag->add('default', false); break; case 'tweetthis_smartify': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_TWITTER_TWEETTHIS_SMARTIFY); $propbag->add('description', PLUGIN_EVENT_TWITTER_TWEETTHIS_SMARTIFY_DESC); $propbag->add('default', false); break; case 'show_shorturl': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_EVENT_TWITTER_SHOW_SHORTURL); $propbag->add('description', PLUGIN_EVENT_TWITTER_SHOW_SHORTURL_DESC); $propbag->add('default', false); break; // General case 'general_title': $propbag->add('type', 'content'); $propbag->add('default', '

' . PLUGIN_EVENT_TWITTER_GENERAL_TITLE . '

'); break; case 'plugin_rel_url': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_PLUGIN_EVENT_REL_URL); $propbag->add('description', PLUGIN_EVENT_TWITTER_PLUGIN_EVENT_REL_URL_DESC); $propbag->add('default', str_replace('//', '/', $serendipity['serendipityHTTPPath'] . preg_replace('@^.*(/plugins.*)@', '$1', dirname(__FILE__)))); break; case 'general_oa_consumerdesc': $propbag->add('type', 'content'); $propbag->add('default', PLUGIN_EVENT_TWITTER_GENERALCONSUMER); break; case 'general_oa_consumerkey': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_CONSUMER_KEY); $propbag->add('description', PLUGIN_EVENT_TWITTER_CONSUMER_KEY_DESC); $propbag->add('default', ''); break; case 'general_oa_consumersecret': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_CONSUMER_SECRET); $propbag->add('description', PLUGIN_EVENT_TWITTER_CONSUMER_KEY_DESC); $propbag->add('default', ''); break; } // Process all extra identities: for ($idx=2; $idx<=$identitycount; $idx++) { switch($name) { case 'id_title'. $idx: $propbag->add('type', 'content'); $propbag->add('default', '

' . PLUGIN_EVENT_TWITTER_IDENTITY . " ($idx)

"); break; case 'id_service'. $idx: $propbag->add('type', 'select'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ACCOUNT_SERVICE); $propbag->add('description', PLUGIN_EVENT_TWITTER_ACCOUNT_SERVICE_DESC); $propbag->add('select_values', $id_services); $propbag->add('default', 'twitter'); break; case 'twittername'. $idx: $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ACCOUNT_NAME); $propbag->add('description', PLUGIN_EVENT_TWITTER_ACCOUNT_NAME_DESC); break; case 'twitterpwd'. $idx: if (!$this->get_config('id_service'. $idx) OR $this->get_config('id_service'. $idx) == "identica"){ $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_TWITTER_ACCOUNT_PWD); $propbag->add('description', PLUGIN_EVENT_TWITTER_ACCOUNT_PWD_DESC); $propbag->add('input_type', 'password'); } break; case 'twitteroa_consumer_key'. $idx: $this->handleConfig('twitteroa_consumer_key', $propbag, $idx); break; case 'twitteroa_consumer_secret'. $idx: $this->handleConfig('twitteroa_consumer_secret', $propbag, $idx); break; case 'twitteroa_sign_in'. $idx: $this->handleConfig('twitteroa_sign_in', $propbag, $idx); break; } } return true; } function get_default_announceformat() { // Compatiblity to old versions: $default_prefix = $this->get_config('anounce_prefix'); //'blog update: '; if (!empty($default_prefix)) { $default_prefix = trim($default_prefix) . ' '; } else { $default_prefix = 'blog update: '; } $format = $default_prefix . '#title# #link#'; if (serendipity_db_bool($this->get_config('announce_with_all_tags',false))) { $format .= ' #tags#'; } return $format; } function get_urlshortener() { $urlshortener = new UrlShortener(); $bitlylogin = $this->get_config('announce_bitly_login'); $bitlyapikey = $this->get_config('announce_bitly_apikey'); $yourlsurl = $this->get_config('announce_yourls_url'); $yourlsapikey = $this->get_config('announce_yourls_apikey'); $piratlyapikey = $this->get_config('announce_piratly_apikey','0'); $this->log("blogin:" . $bitlylogin . " bapi: " . $bitlyapikey); $urlshortener->setBitlyLogin($bitlylogin, $bitlyapikey); $this->log("slogin:" . $urlshortener->bitly_login . " sapi: " . $urlshortener->bitly_apikey); $urlshortener->setPiratlyToken($piratlyapikey); $urlshortener->setYourlsLogin($yourlsurl,$yourlsapikey); return $urlshortener; } function generate_content(&$title) { $title = PLUGIN_EVENT_TWITTER_NAME; } function event_hook($event, &$bag, &$eventData, $addData = null) { global $serendipity; static $cache = null; static $method = null; $hooks = &$bag->get('event_hooks'); if (isset($hooks[$event])) { switch($event) { case 'css': if (strpos($eventData, '#twitter_update_list')) { // class exists in CSS, so a user has customized it and we don't need default return true; } $this->addToCSS($eventData); return true; break; case 'backend_header': $this->add_backend_header_parts(); return true; case 'backend_publish': // If signaled, we don't want to announce, don't do it! if (isset($serendipity['POST']['properties']['microblogging_dontannounce'])) { return true; } // eventData is the entry here return $this->twitter_published_entry($eventData); break; case 'backend_delete_entry': $this->entry_deleted((int)$eventData); return true; break; case 'external_plugin': $parts = explode('_',$eventData); $command = $parts[0]; if ($command== 'cacheplugintwitter') { $next_check = (int)$this->updateTwitterTimelineCache($parts); $this->show_img(dirname(__FILE__) . '/img/pixel.png', (int)$next_check); return true; } $parts = explode('=',$eventData); $command = $parts[0]; $fparts = explode('&', $parts[1]); if ($command=="tweetback") { if (!$_SESSION['serendipityAuthedUser']) { echo "DON'T HACK!
"; return true; } $article_url = preg_replace('@^tweetback=@','',$eventData); $article_url=$this->urldecode($article_url); if (empty($article_url)) { echo "Dont hack!"; } $shorturls = $this->create_short_urls($article_url); $entries = $entries = $this->search($article_url, null); if (is_array($entries)) { $this->debug_entries($entries, $article_url, $shorturls); } else { echo "

ERROR while fetching search results for URL $article_url
Might be a Twitter Overload.
Try again later

"; } return true; } else if ($command=="gtweetback.png") { $nextcheck = $this->check_tweetbacks_global(); if (empty($nextcheck)) $nextcheck = time() + (30 * 60); // Default for hackers $this->show_img(dirname(__FILE__) . '/img/pixel.png', $nextcheck, 'image/png'); return true; } else if ($command == "twitteroa-del") { $this->twitteroalog($command); // Remove current twitter OAuth key and token to allow to re-connect if (!serendipity_userLoggedIn()) { die ("Don't hack!"); } $idx = $fparts[0]; // Remove access tokens $u = $this->get_config('twittername' . $idx); $kd = $this->set_config('twitteroa_key_' . $idx . $u, ''); $td = $this->set_config('twitteroa_token_' . $idx . $u, ''); // Remove old application, so it will change to the s9y app next time: $csecret = $this->set_config('twitteroa_consumer_secret' . $idx, ''); $ckey = $this->set_config('twitteroa_consumer_key' . $idx, ''); serendipity_die('

' . PLUGIN_EVENT_TWITTER_VERBINDUNG_DEL_OK . '

' . PLUGIN_EVENT_TWITTER_CLOSEWINDOW . '
'); return true; } else if ($command == "twitteroa-redirect") { $this->twitteroalog($command); if (!serendipity_userLoggedIn()) { die ("Don't hack!"); } $idx = $fparts[0]; $u = $this->get_config('twittername' . $idx); $kd = $this->get_config('twitteroa_key_' . $idx .$u); $td = $this->get_config('twitteroa_token_' . $idx . $u); $ckey = $this->get_config('twitteroa_consumer_key' . $idx); $csecret = $this->get_config('twitteroa_consumer_secret' . $idx); require_once(dirname(__FILE__) . '/twitteroauth/twitteroauth.php'); $twittername = $u; $callbackurl = $serendipity['baseURL'] . $serendipity['indexFile'] . '?/' . TwitterPluginFileAccess::get_permaplugin_path() . '/twitteroa-callback=' . $idx . "&twittername=" . $twittername; define('CONSUMER_KEY', $ckey); define('CONSUMER_SECRET', $csecret); define('OAUTH_CALLBACK', $callbackurl); /* Build TwitterOAuth object with client credentials. */ $connection = new TwitterOAuth($ckey, $csecret); /* Get temporary credentials. */ $request_token = $connection->getRequestToken(OAUTH_CALLBACK); /* Save temporary credentials to session. */ $_SESSION['oauth_token'] = $token = $request_token['oauth_token']; $_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret']; /* If last connection failed don't display authorization link. */ switch ($connection->http_code) { case 200: /* Build authorize URL and redirect user to Twitter. */ $url = $connection->getAuthorizeURL($token); header('Location: ' . $url); exit; break; default: serendipity_die('

' . PLUGIN_EVENT_TWITTER_VERBINDUNG_ERROR . '

' . print_r($connection, true) . '
' . print_r($request_token, true) . '
' . print_r($_SESSION, true) . '
' . print_r($_REQUEST, true) . '
' . PLUGIN_EVENT_TWITTER_CLOSEWINDOW . '
'); } return true; } else if ($command == "twitteroa-callback") { $this->twitteroalog($command); if (!serendipity_userLoggedIn()) { die ("Don't hack!"); } $idx = $fparts[0]; $u = $this->get_config('twittername' . $idx); $kd = $this->get_config('twitteroa_key_' . $idx .$u); $td = $this->get_config('twitteroa_token_' . $idx . $u); $ckey = $this->get_config('twitteroa_consumer_key' . $idx); $csecret = $this->get_config('twitteroa_consumer_secret' . $idx); require_once(dirname(__FILE__) . '/twitteroauth/twitteroauth.php'); define('CONSUMER_KEY', $ckey); define('CONSUMER_SECRET', $csecret); /* If the oauth_token is old redirect to the connect page. */ if (isset($_REQUEST['oauth_token']) && $_SESSION['oauth_token'] !== $_REQUEST['oauth_token']) { $_SESSION['oauth_status'] = 'oldtoken'; $url = $serendipity['baseURL'] . $serendipity['indexFile'] . '?/' . TwitterPluginFileAccess::get_permaplugin_path() . '/twitteroa-redirect=' . $idx; header('Location: ' . $url); exit; } /* Create TwitteroAuth object with app key/secret and token key/secret from default phase */ $connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $_SESSION['oauth_token'], $_SESSION['oauth_token_secret']); /* Request access tokens from twitter */ $access_token = $connection->getAccessToken($_REQUEST['oauth_verifier']); $this->set_config('twitteroa_key_' . $idx . $u, $access_token['oauth_token']); $this->set_config('twitteroa_token_' . $idx . $u, $access_token['oauth_token_secret']); /* Remove no longer needed request tokens */ unset($_SESSION['oauth_token']); unset($_SESSION['oauth_token_secret']); /* If HTTP response is 200 continue otherwise send to connect page to retry */ if (200 == $connection->http_code) { serendipity_die('

' . PLUGIN_EVENT_TWITTER_VERBINDUNG_OK . '

' . PLUGIN_EVENT_TWITTER_CLOSEWINDOW . '
'); } else { serendipity_die('

' . PLUGIN_EVENT_TWITTER_VERBINDUNG_ERROR . '

' . print_r($connection, true) . '
' . print_r($access_token, true) . '
' . print_r($_SESSION, true) . '
' . print_r($_REQUEST, true) . '
' . PLUGIN_EVENT_TWITTER_CLOSEWINDOW . '
'); } return true; } return false; break; case 'entry_display': $this->display_entry($eventData, $addData); return true; case 'backend_frontpage_display': if ($this->get_config('tweeter_show', 'disable') == 'frontpage') { $this->display_twitter_client(false); } return true; case 'backend_sidebar_entries': if ($serendipity['version'][0] == '1') { if ($this->get_config('tweeter_show', 'disable') == 'sidebar') { ?> get_config('tweeter_show', 'disable') == 'sidebar') { ?>
  • ' . PLUGIN_EVENT_TWITTER_TWEETER_SIDEBARTITLE . ''; $this->display_twitter_client(true); return true; case 'frontend_footer': $this->display_frontend_footer(); return true; case 'frontend_saveComment': $this->hook_saveComment($eventData, $addData); return true; case 'backend_display': if (!serendipity_db_bool($this->get_config('announce_articles'))) { return true; } if (isset($serendipity['POST']['properties']['microblogging_tagList'])) { $tagList = $serendipity['POST']['properties']['microblogging_tagList']; } else { $tagList = ''; } if (isset($serendipity['POST']['properties']['microblogging_dontannounce'])) { $checked_dontannounce = "checked='checked'"; } else { $checked_dontannounce = ''; } if (serendipity_db_bool($this->get_config('announce_articles_default_no'))) { $checked_dontannounce = "checked='checked'"; } if ($serendipity['version'][0] == '1') { ?>
    />

    >
    get_config('highest_id_global','0')<$highest_id_single) { $this->set_config('highest_id_global', TwitterPluginDbAccess::find_highest_twitterid()); } // patch old config if ('default' == $this->get_config('tweetback_moderate')) { $this->set_config('tweetback_moderate','approved'); } if ('snipr' == $this->get_config('anounce_url_service')) { $this->set_config('7ax'); } $this->check_tweetbacks_global(true); } function install() { TwitterPluginDbAccess::install($this); } function addToCSS(&$eventData) { $eventData .= ' /* plugin twitter */ #twitter_update_list { list-style: none; padding-left: 0; } a.twitter_update_time { display: block; padding-bottom: 5px; } '; } function add_backend_header_parts() { $cssfilename = TwitterPluginFileAccess::get_file_from_template('tweeter/serendipity_event_twitter_tweeter.css', $this->get_config('plugin_rel_url')); echo '' . "\n"; $jsfilename = $this->get_config('plugin_rel_url') . '/tweeter/serendipity_event_twitter_tweeter.js'; echo '' . "\n"; } function display_frontend_footer() { global $serendipity; if (!serendipity_db_bool($this->get_config('do_tweetbacks',false))) return false; $pluginurl = $serendipity['baseURL'] . $serendipity['indexFile'] . '?/' . TwitterPluginFileAccess::get_permaplugin_path(); // add pixel doing tweetback check to each visible entry footer $tweetbackpng_url = $pluginurl . '/gtweetback.png'; echo 'tweetbackcheck'; } /** * Entry deleted event fetched. Delete all data, not needed anymore. */ function entry_deleted($entryId) { TwitterPluginDbAccess::entry_deleted($entryId); } function check_tweetbacks_save_comment($article_id, $entry, $comment_type, $strip_tags = false) { $commentInfo = array(); $commentInfo['title'] = $entry[TWITTER_SEARCHRESULT_REALNAME] . " via Twitter"; $commentInfo['name'] = $entry[TWITTER_SEARCHRESULT_REALNAME]; $commentInfo['url'] = $this->comment_url($entry); $commentInfo['email'] = $entry[TWITTER_SEARCHRESULT_EMAIL]; $comment = $entry[TWITTER_SEARCHRESULT_TWEET]; if ($strip_tags) { $comment = strip_tags($comment); } if (LANG_CHARSET!='UTF-8' && function_exists("mb_convert_encoding")) { $comment = mb_convert_encoding($comment, LANG_CHARSET); } $commentInfo['comment'] = $comment; $commentInfo['time'] = strtotime($entry[TWITTER_SEARCHRESULT_PUBDATE]); $commentInfo['source'] = 'tweetback'; $this->log("Tweetback save: title=[" . $commentInfo['title'] ."], comment=[" . $commentInfo['comment'] . "] articleid=[$article_id]"); // patch old config if ('default' == $this->get_config('tweetback_moderate')) { $this->set_config('tweetback_moderate','approved'); } $comment_moderation = $this->get_config('tweetback_moderate','approved'); if ('save'==$comment_moderation) { // save comment starts spam plugin. This might intervent the saving, but we don't want that here. // If we have more than 1 tweetback, at least the min posting freq for one IP will hit. return serendipity_saveComment($article_id, $commentInfo, $comment_type, 'tweetback'); } else { $ca = array(); $this->hook_saveComment($ca, $commentInfo); return serendipity_insertComment($article_id, $commentInfo, $comment_type, 'tweetback', $ca); } } function hook_saveComment(&$ca, &$commentInfo) { // is this our comment to be saved? if (empty($commentInfo) || $commentInfo['source']!='tweetback') return; $comment_moderation = $this->get_config('tweetback_moderate','approved'); if ('save'!=$comment_moderation) { $commentInfo['status'] = $comment_moderation; if ('pending' == $comment_moderation) { $ca['moderate_comments'] = true; } else if ('approved' == $comment_moderation) { $ca['moderate_comments'] = false; } else if ('default' == $comment_moderation) { // this is an old configuration $ca['moderate_comments'] = false; } } $this->log("hook_saveComment end"); } function check_tweetbacks_global($complete = false) { global $serendipity; $this->log("Check global"); if (!serendipity_db_bool($this->get_config('do_tweetbacks'))) return false; $lastcheck = $this->get_config('last_check_global'); $check_freq = $this->get_config('tweetback_check_freq',30); if (!is_numeric($check_freq) || $check_freq < 5) { $check_freq = 5; } $check_freq = $check_freq * 60; // we need seconds if (!$complete && !empty($lastcheck) && (time() - $lastcheck) < $check_freq){ // Search already done. return $lastcheck + $check_freq; } // TODO: This file sema is blocking! wtf?! if (!($fp=TwitterPluginFileAccess::get_lock(0))) { $this->log("Sema is blocking."); return time() + $check_freq; // someone else ist processing the global check } $baseUrl = $serendipity['baseURL']; $permalinkRegex = '@(' . $baseUrl . '.*'. serendipity_makePermalinkRegex($serendipity['permalinkStructure'], 'entry') . ')/?@i'; if ($complete) { $old_since_id ='0'; } else { $old_since_id = $this->get_config('highest_id_global'); } $this->log("old_since_id [$old_since_id]"); $comment_type = $this->get_config('tweetback_type','TRACKBACK'); $ignore_names = explode(',', $this->get_config('ignore_tweetbacks_by_name', $this->get_config('twittername'))); $search_since_id = "0"; if (!empty($old_since_id)) { $search_since_id = $old_since_id; } // Start searching $idx = $this->get_config('twitter_generic_acc', '1'); if ($idx == '1') { $idx = ''; } $connection = $this->twitteroa_connect($idx); $twitterapi = new TwitterOAuthApi($connection); $twittersearch = $this->generate_domain_url(false) . "&since_id=".$search_since_id; $entries = $twitterapi->search($twittersearch); if (is_array($entries) && !empty($entries) ) { // reverse the entries to get oldest first! $entries = array_reverse( $entries, true ); $redirCheck = new RedirectCheck(); $validated_entries = array(); foreach ($entries as $entry) { $writer = $entry[TWITTER_SEARCHRESULT_LOGIN]; // First check if the tweets autor should be ignored: $ignore = false; foreach( $ignore_names as $ignore_name) { $ignore = strtoupper(trim($ignore_name)) == strtoupper($writer); if ($ignore) break; } if ($ignore) continue; // Check wether this tweet is blog article related: $tweetmatches = false; // Check all expanded urls: if (!empty($entry[TWITTER_SEARCHRESULT_URL_ARRAY])) { foreach ($entry[TWITTER_SEARCHRESULT_URL_ARRAY] as $url) { $url = $redirCheck->get_final_url($url); $tweetmatches = preg_match($permalinkRegex, $url, $matches); if ($tweetmatches) break; // Found it! } } // If no URL matches, try the tweet itself: if (!$tweetmatches) { $tweet = $entry[TWITTER_SEARCHRESULT_TWEET]; !$tweetmatches = preg_match($permalinkRegex, $tweet, $matches); } // If we found a match, add it to the validated entries if ($tweetmatches) { $this->log("Tweet matches!"); $match = array('id' => $matches[2], 'entry' => $entry); $validated_entries[] = $match; } } } //is array $entries end // Save all comments and evaluate highest ids: $highest_ids = array(); if (is_array($validated_entries) && !empty($validated_entries) ) { foreach ($validated_entries as $valid) { $comment_saved = false; $article_id = $valid['id']; $entry = $valid['entry']; $test_highest_id = null; if (!empty($highest_ids[$article_id])) { $test_highest_id = $highest_ids[$article_id]['high_id']; } if (empty($test_highest_id)) { // load old highest id of the article $last_info = TwitterPluginDbAccess::load_tweetback_info($article_id, $this); $test_highest_id = empty($last_info)?null:$last_info['lasttweetid']; $highest_ids[$article_id] = array('high_id' => $test_highest_id, 'last_info' => $last_info); } if (empty($highest_ids[$article_id]['last_info']) || empty($highest_ids[$article_id]['last_info']['lasttweetid']) || "{$entry[TWITTER_SEARCHRESULT_ID]}">$highest_ids[$article_id]['last_info']['lasttweetid']) { if ($complete) { // This is called from admin interface echo "
    Found new tweetback for article $article_id: tweetid: {$entry[TWITTER_SEARCHRESULT_ID]}

    "; } $this->check_tweetbacks_save_comment($article_id, $entry, $comment_type, true); $comment_saved = true; } // Remember highest id, if saved and highest id is higher than old one. if ($comment_saved && (empty($test_highest_id) || "{$entry[TWITTER_SEARCHRESULT_ID]}" > "$test_highest_id")) { $highest_ids[$article_id]['high_id'] = "{$entry[TWITTER_SEARCHRESULT_ID]}"; } } } // is array $validated_entries end $global_highest_id = $this->get_config('highest_id_global'); if (empty($global_highest_id)) $global_highest_id = '0'; if (is_array($highest_ids) && !empty($highest_ids) ) { // Save highest ids: foreach( $highest_ids as $article_id => $highest_id_array ) { // remember globaly if (!empty($highest_id_array['high_id']) && $highest_id_array['high_id'] > $global_highest_id) { $global_highest_id = $highest_id_array['high_id']; } // save per article if (empty($highest_id_array['last_info']) || $highest_id_array['high_id']>$highest_id_array['last_info']['lasttweetid']) { TwitterPluginDbAccess::save_highest_id($article_id, $highest_id_array['high_id'], $highest_id_array['last_info']); } } } // is array $highest_ids end $lastcheck = time(); $this->set_config('last_check_global', $lastcheck); $this->set_config('highest_id_global', $global_highest_id); TwitterPluginFileAccess::free_lock(0); return $lastcheck + $check_freq; } function search($article_url, $old_since_id) { if ($this->get_config('twitter_api', 'api10') == 'api10') { $entries = Twitter::search_multiple($article_url, $old_since_id); } else { $idx = $this->get_config('twitter_generic_acc', '1'); if ($idx=='1') $idx = ''; $connection = $this->twitteroa_connect($idx); $entries = TwitterOAuthApi::search_multiple($connection, $article_url, $old_since_id); } return array_reverse ( $entries, true ); } function comment_url($entry) { $use_url_kind = $this->get_config('tweetback_url','status'); switch ($use_url_kind) { case 'profile': $comment_url = $entry[TWITTER_SEARCHRESULT_URL_AUTOR]; break; case 'weburl': $api = new Twitter(); $user = $api->userinfo($entry[TWITTER_SEARCHRESULT_LOGIN]); if (!empty($user) && !empty($user->url)) { $comment_url = $user->url; } else { $comment_url = $entry[TWITTER_SEARCHRESULT_URL_TWEET]; } break; default: // status $comment_url = $entry[TWITTER_SEARCHRESULT_URL_TWEET]; } return $comment_url; } function create_update_from_entry($entry, $announce_format, $checkUrlLen = false) { global $serendipity; $entryurl = $this->generate_article_url($entry); $short_url = $this->default_shorturl($entryurl); // Check for real URL length after twitter shortened it: if ($checkUrlLen) { $this->twitter_check_config(); if (substr($short_url,0,5) == 'https') { $url_len = $this->get_config('twitter_config_https_len'); } else { $url_len = $this->get_config('twitter_config_http_len'); } } if (empty($url_len)) $url_len = strlen($short_url); // Fallback, if we were not able to detect it $url_placeholder = "#"; for ($i=1; $i<$url_len-2;$i++) { $url_placeholder .= $i; } $url_placeholder .= "#"; $author = !empty($entry['author'])?$entry['author']:$serendipity['serendipityRealname']; $announce_format = str_replace( array('#author#','#autor#','#link#'), array($author,$author,$url_placeholder), $announce_format); $title = $entry['title']; $tags_marker = '#tags#'; $announce_format_notags = trim(str_replace($tags_marker,'',$announce_format)); // Check for tags: $tagsnotused = array(); if (serendipity_db_bool($this->get_config('announce_with_tags',false)) && !empty($serendipity['POST']['properties']) && !(empty($serendipity['POST']['properties']['freetag_tagList']) && empty($serendipity['POST']['properties']['microblogging_tagList'])) && strlen($announce_format_notags)<140) { $taglist = ''; if (!empty($serendipity['POST']['properties']['microblogging_tagList'])) { $taglist = $serendipity['POST']['properties']['microblogging_tagList']; } else if (!empty($serendipity['POST']['properties']['freetag_tagList'])) { $taglist = $serendipity['POST']['properties']['freetag_tagList']; } if (!empty($taglist)) { $tags = explode(',',$taglist); foreach ($tags as $tag) { $tag = trim($tag); $tag = str_replace(" ","_",$tag); // make tags more twitter alike $test = str_replace('#title#',$title,$announce_format_notags); $len = strlen($title); if (strlen($test) < 140) { // still capacity $title = preg_replace('@(^|\s)(' . $tag . '($|\s))@i'," #$2",$title); if (strlen($title) == $len) $tagsnotused[] = $tag; } else { $tagsnotused[] = $tag; } } } } $update = str_replace('#title#',$title,$announce_format); // Fill up with not used tags if (strstr($announce_format,$tags_marker)) { $added = false; foreach ($tagsnotused as $tag) { $test = str_replace($tags_marker,'#' . $tag . ' ' . $tags_marker,$update); if (strlen($test) <142 + strlen($tags_marker)) { $update = $test; $added = true; } } // remove tags marker now $update = trim(str_replace(array(' ' . $tags_marker,$tags_marker),'',$update)); } // Now fill in shorturl, if needed $update = str_replace($url_placeholder, $short_url, $update); // Change encoding of update to UTF-8 if (LANG_CHARSET!='UTF-8' && function_exists("mb_convert_encoding")) { $update = mb_convert_encoding($update, 'UTF-8', LANG_CHARSET); } return $update; } function twitter_check_config() { $last_config_check = $this->get_config("twitter_last_config_check", 0); $now = time(); $daybefore = $now - (24 * 60 * 60); // One day in seconds if (empty($last_config_check) || $last_config_check<$daybefore) { $api = new Twitter(); $config = $api->get_twitter_config(); if (!empty($config)) { $max_http = $config->short_url_length; $max_https = $config->short_url_length_https; $this->set_config('twitter_last_config_check', $now); $this->set_config('twitter_config_http_len', $max_http); $this->set_config('twitter_config_https_len', $max_https); } } } function twitter_published_entry( $entry ) { global $serendipity; if (!serendipity_db_bool($this->get_config('announce_articles'))) return false; // Do not announce future entries! if (empty($entry['timestamp']) || time()<$entry['timestamp']) return false; $announce_account_list = explode('^',$this->get_config('announce_via_accounts')); if (count($announce_account_list)==0) return true; $announce_format = trim($this->get_config('announce_format', $this->get_default_announceformat())); $updates = array(); echo ""; return true; } function twitteroa_connect($idx = '') { require_once(dirname(__FILE__).'/twitteroauth/twitteroauth.php'); $u = $this->get_config('twittername' . $idx); $kd = $oauth_token = $this->get_config('twitteroa_key_' . $idx .$u); $td = $oauth_token_secret = $this->get_config('twitteroa_token_' . $idx . $u); $ckey = $consumer_key = $this->get_config('twitteroa_consumer_key' . $idx); $csecret = $consumer_secret = $this->get_config('twitteroa_consumer_secret' . $idx); /* Create a TwitterOauth object with consumer/user tokens. */ $connection = new TwitterOAuth($consumer_key, $consumer_secret, $oauth_token, $oauth_token_secret); return $connection; } function twitter_published_entry_to_account($account_index, $account_name, $account_pwd, $account_type, $update, $geo_lat = NULL, $geo_long = NULL ) { if ($account_type == "identica"){ $api = new Twitter($account_type=='identica'); $status = $api->update($account_name, $account_pwd, $update, $geo_lat, $geo_long); } else { $connection = $this->twitteroa_connect($account_index); $api = new TwitterOAuthApi($connection); $status = $api->update($update, $geo_lat, $geo_long); } // Information about status update echo "
  • $account_type update for $account_name: [" . mb_convert_encoding($update, LANG_CHARSET) . "]"; if (!empty($geo_lat) && !empty($geo_long)) { echo ", Geo: lat=$geo_lat / long=$geo_long"; } echo "
  • "; if (PLUGIN_TWITTER_DEBUG) { echo "
  • Status $status
  • "; } } function twitteroa_global_consumersettings() { // Return local client setup with fallback to the s9y client $result = array(); $result['key'] =$this->get_config('general_oa_consumerkey', PLUGIN_TWITTER_OAUTH_TWITTER_CONSUMERKEY); $result['secret'] =$this->get_config('general_oa_consumersecret', PLUGIN_TWITTER_OAUTH_TWITTER_CONSUMERSECRET); return $result; } function default_shorturl( $url ) { $default = $this->get_config('anounce_url_service','7ax.de'); $shorturls = TwitterPluginDbAccess::load_short_urls( $url, array($default) ); if (!empty($shorturls[$default])) return $shorturls[$default]; $shorturls = array(); $shorter = $this->get_urlshortener(); $shorter->put_shorturl($this->get_config('anounce_url_service','7ax.de'), $url, $shorturls); if (!empty($shorturls[$this->get_config('anounce_url_service','7ax.de')])) { TwitterPluginDbAccess::save_short_urls( $url, $shorturls); return $shorturls[$this->get_config('anounce_url_service','7ax.de')]; } else { return $url; } } /** * adds tweetthis, dentthis and "check tweetbacks" (if logged in) to footer */ function display_entry(&$eventData, $addData) { global $serendipity; if ($addData['preview']) return false; $do_tweetbacks = serendipity_db_bool($this->get_config('do_tweetbacks',false)); $do_tweetthis = serendipity_db_bool($this->get_config('do_tweetthis',false)); $do_identicathis = serendipity_db_bool($this->get_config('do_identicathis',false)); $do_smartify = serendipity_db_bool($this->get_config('tweetthis_smartify',false)); $show_shorturl = serendipity_db_bool($this->get_config('show_shorturl',false)); //if (!$do_tweetbacks && !$do_tweetthis && !$do_identicathis) return false; if (!is_array($eventData)) return false; $pluginurl = $serendipity['baseURL'] . $serendipity['indexFile'] . '?/' . TwitterPluginFileAccess::get_permaplugin_path(); if ($do_tweetthis || $do_identicathis) { $tweetthis_format = $this->get_config('tweetthis_format','#title# #link#'); $tweetthis_button = $this->get_config('tweetthis_button','black'); $tweetthis_target = ''; if (serendipity_db_bool($this->get_config('tweetthis_newwindow',false))) { $tweetthis_target = ' target="_blank"'; } } $event_index = 0; foreach ($eventData as $entry) { // Test for nonsense data (or static pages) if (!isset($entry['id']) || !is_numeric($entry['id']) || (int)$entry['id']<1) { continue; } $entryurl = $this->generate_article_url($entry); // Show tweetback check link only logged in users //if ($do_tweetbacks && $_SESSION['serendipityAuthedUser'] && $addData['extended']) { if ($_SESSION['serendipityAuthedUser'] && $addData['extended']) { $checkurl = $pluginurl. '/tweetback=' . $this->urlencode($entryurl); $tweetback_check_msg = '
    check tweetbacks
    '; $eventData[$event_index]['add_footer'] .= $tweetback_check_msg; } // add shorturl to entryfooter if ($show_shorturl) { $shorturl = $this->default_shorturl($entryurl); $onclick = (function_exists('serendipity_specialchars') ? serendipity_specialchars(PLUGIN_EVENT_TWITTER_SHORTURL_ON_CLICK) : htmlspecialchars(PLUGIN_EVENT_TWITTER_SHORTURL_ON_CLICK, ENT_COMPAT, LANG_CHARSET)); if ($do_smartify) { // emit smarty tag only $eventData[$event_index]['url_shorturl'] = $shorturl; } else { $eventData[$event_index]['add_footer'] .= ''; } } if ($do_tweetthis || $do_identicathis) { $update = $update = $this->create_update_from_entry($eventData[$event_index], $tweetthis_format); if ($do_tweetthis) { $url_tweetthis = 'http://twitter.com/intent/tweet?text=' . urlencode($update) ; if ($do_smartify) { // emit smarty tag only $eventData[$event_index]['url_tweetthis'] = $url_tweetthis; } else { // http://twitter.com/home/?status=Tweet+This%2C+a+WordPress+Plugin+for+Twitter+http://richardxthripp.thripp.com/?p=646 $button_url = $this->get_config('plugin_rel_url') . '/img/tt-micro-' . $this->get_config('tweetthis_button','black') . '.png'; $tweetthis = ''. PLUGIN_EVENT_TWITTER_TWEETTHIS_TITLE .''; $eventData[$event_index]['add_footer'] .= $tweetthis; } } if ($do_identicathis) { $url_dentthis = 'http://identi.ca/notice/new?status_textarea=' . urlencode($update); if ($do_smartify) { // emit smarty tag only $eventData[$event_index]['url_dentthis'] = $url_dentthis; } else { // http://twitter.com/home/?status=Tweet+This%2C+a+WordPress+Plugin+for+Twitter+http://richardxthripp.thripp.com/?p=646 $button_url = $this->get_config('plugin_rel_url') . '/img/it-micro-' . $this->get_config('tweetthis_button','black') . '.png'; $tweetthis = ''. PLUGIN_EVENT_TWITTER_TWEETTHIS_TITLE .''; $eventData[$event_index]['add_footer'] .= $tweetthis; } } } $event_index++; } } function generate_article_url( $entry ) { global $serendipity; $urlparts = @parse_url($serendipity['baseURL']); $server = $urlparts['scheme'] . '://' . $urlparts['host']; if (!empty($urlparts['port'])) $server = $server . ':' . $urlparts['port']; $relurl = serendipity_archiveURL($entry['id'], $entry['title'], 'serendipityHTTPPath', true, array('timestamp' => $entry['timestamp'])); return $server . $relurl; } function generate_domain_url($addScheme = true) { global $serendipity; $urlparts = @parse_url($serendipity['baseURL']); $server = ($addScheme?$urlparts['scheme'] . '://':"") . $urlparts['host']; $this->log("server= " . $server); return $server; } function create_short_urls( $article_url ) { $selected_services = array('raw'); // preload shorturls, we have fetched before $shorturls = TwitterPluginDbAccess::load_short_urls( $article_url, $selected_services ); // remember already known shorturls $loaded_shorturls = $shorturls; $shorter = $this->get_urlshortener(); foreach ($selected_services as $service) { $shorter->put_shorturl($service, $article_url, $shorturls); } TwitterPluginDbAccess::save_short_urls( $article_url, $shorturls, $loaded_shorturls ); return $shorturls; } /** * Return binary response for an image */ function show_img($filename, $nextcheck=null, $mime_type='image/png') { if (empty($nextcheck)) $nextcheck = time() + (30*60); // try again in 30min, if nothing was specified. header("Content-type: $mime_type"); header("Date: " . date("D, d M Y H:i:s T")); header("Cache-Control: public, max-age=" . ((int)$nextcheck - time()) , true); header("Pragma:", true); $expires_txt = date("D, d M Y H:i:s T",(int)$nextcheck); $fp = @fopen($filename, "rb"); if ($fp) { header('X-TweetBackPng: Found'); $filemtime = filemtime($filename); header("Content-Length: ". filesize($filename), true); header("Last-Modified: " . date("D, d M Y H:i:s T", $filemtime), true); header("Expires: $expires_txt". true); fpassthru($fp); fclose($fp); } else { header('X-TweetBackPng: No-Image'); header("Content-Length: 0", true); header("Last-Modified: " . date("D, d M Y H:i:s T"), true); header("Expires: $expires_txt". true); } return true; } /** * Returns a URL encoded and signed variable. */ function urlencode($url) { $hash = md5($this->instance_id . $url); # return $hash . str_replace ('_', '%5F', urlencode($url)); return $hash . base64_encode($url);//changed by Ruben } function urldecode($url) { $hash = substr($url, 0, 32); # $real_url = urldecode(substr($url, 32)); $real_url = base64_decode(substr($url, 32));//changed by Ruben if ($hash == md5($this->instance_id . $real_url)) { // Valid hash was found. return $real_url; } else { // Invalid hash. return ''; } } function debug_entries($entries, $article_url, $shorturls) { // Newst first $entries = array_reverse( $entries ); echo "

    Tweetbacks Statistics

    "; echo "URL: $article_url
    "; echo "

    Short URLs searched

    "; echo ""; echo "

    Tweets found

    "; echo "Found " . count($entries) . " tweets.
    "; echo ""; } function updateTwitterTimelineCache($parts){ global $serendipity; if (count($parts)<5) return time() + (60 * 60); // params corrupted next try allowed one minute later // Do we need to do OAuth? if (count($parts)>6) { $idx_twitter = $parts[5]; $idxmd5 = $parts[6]; $idxmd5_test = md5(serendipity_event_twitter::pluginSecret() . "_{$idx_twitter}"); if ($idxmd5_test != $idxmd5) { // Seems to be a hack! return time() + (60 * 60); // params corrupted next try allowed one minute later } } $show_rt = false; if (count($parts)>7) { $features = $parts[7]; $show_rt = (strpos($features, 'r')!==false); } $cachetime = (int)$parts[4]; $service = $parts[1]; $username = str_replace('!', '_', $parts[2]); $cache_user = md5($service) . md5($username); $cachefile = $serendipity['serendipityPath'] . PATH_SMARTY_COMPILE . "/twitterresult.$cache_user.json"; $nextcheck = time() + (int)$cachetime; if (file_exists($cachefile)) { $nextcheck = filemtime($cachefile) + $cachetime; } if (!file_exists($cachefile) || filemtime($cachefile) < (time()-$cachetime)) { $number = str_replace("!","_",$parts[3]); $error=200; // Default is: All OK if (!empty($idx_twitter)) { $search_twitter_uri = 'https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=' . $username . '&count=' . $number . '&trim_user=true'; if (!$show_rt) $search_twitter_uri .= '&include_rts=false'; if ($idx_twitter=='1') $idx_twitter=''; // First cfg is saved with empty suffix! $connection = $this->twitteroa_connect($idx_twitter); $connection->decode_json = false; $response = $connection->get($search_twitter_uri); } else { if ($service == 'identi.ca') { $followme_url = 'http://identi.ca/' . $username; $status_url = 'http://identi.ca/notice/'; $JSONcallback = 'identicaCallback2'; $service_url = 'http://identi.ca/api'; $search_twitter_uri = $service_url . '/statuses/user_timeline/' . $username . '.json?count=' . $number; } else { $followme_url = 'https://twitter.com/' . $username; $service_url = 'https://twitter.com'; $status_url = 'https://twitter.com/' . $username . '/statuses/'; $JSONcallback = 'twitterCallback2'; $search_twitter_uri = 'https://api.twitter.com/1/statuses/user_timeline.json?screen_name=' . $username . '&count=' . $number; } if (function_exists('serendipity_request_url')) { $response = serendipity_request_url($search_twitter_uri); $error = $serendipity['last_http_request']['responseCode']; } else { require_once S9Y_PEAR_PATH . 'HTTP/Request.php'; serendipity_request_start(); $req = new HTTP_Request($search_twitter_uri); $req->sendRequest(); $response = trim($req->getResponseBody()); $error = $req->getResponseCode(); serendipity_request_end(); } } $this->log("error: {$error}"); if ($error==200 && !empty($response)) { $this->log("Writing response into cache."); $fp = fopen($cachefile, 'w'); fwrite($fp, serialize($response)); fflush($fp); fclose($fp); $nextcheck = time() + (int)$cachetime; $this->log("Writing response into cache. DONE"); } } return $nextcheck; } function curPageURL() { return $_SERVER["REQUEST_URI"]; } function log($message){ if (!PLUGIN_TWITTER_DEBUG) return; $fp = fopen(TwitterPluginFileAccess::get_cache_prefix() . '.log','a'); fwrite($fp, date('Y.m.d H:i:s') . " - " . $message . "\n"); fflush($fp); fclose($fp); } function load_timeline() { $status_timeline = array( "public_timeline", "home_timeline", "friends_timeline", "user_timeline", "mentions", "retweeted_by_me", "retweeted_to_me", "retweets_of_me"); return $status_timeline; } function load_identities() { $idcount = $this->get_config('id_count',1); if (!is_numeric($idcount)) $idcount = 1; $identities = array(); $identities[] = $this->get_config('id_service','twitter') . ': ' . $this->get_config('twittername'); for ($idx=2; $idx<=$idcount; $idx++) { $identities[] = $this->get_config('id_service'. $idx,'twitter') . ': ' . $this->get_config('twittername'. $idx); } return $identities; } function display_twitter_client($tweeter_in_sidbar = false) { $identities = $this->load_identities(); $status_timeline = $this->load_timeline(); $tweeter_has_timeline = ($this->get_config('tweeter_history', false) === true); if ($_POST['tweeter_timeline']){ $pstatus_timeline = $_POST['tweeter_timeline']; } else { $pstatus_timeline = $this->get_config('tweeter_timeline'); } // Always remember last set identity $val_identitiy = $_POST['tweeter_account']; $acc_number = ''; if (empty($val_identitiy) || $val_identitiy==0) { $account_name = $this->get_config('twittername',''); $account_pwd = $this->get_config('twitterpwd',''); $account_type = $this->get_config('id_service','twitter'); } else { $acc_number = (int)$val_identitiy + 1; $account_name = $this->get_config('twittername' . $acc_number,''); $account_pwd = $this->get_config('twitterpwd' . $acc_number,''); $account_type = $this->get_config('id_service' . $acc_number,'twitter'); } // Display client if($this->get_config('tweeter_show', 'disable') != 'disable'){ if (isset($_POST['tweeter_submit'])) { if(isset($_POST['tweet'], $_POST['shorturl'])){ if($_POST['shorturl'] !== 'http://' && !empty($_POST['shorturl'])){ $val_short = $this->default_shorturl($_POST['shorturl']); if($val_short == $_POST['shorturl']){ $val_short = 'ERROR'; } $val_tweet = $_POST['tweet'] . $val_short; $val_short = ''; } elseif(!empty($_POST['tweet'])){ $update = $_POST['tweet']; // Change encoding of update to UTF-8 if (LANG_CHARSET!='UTF-8' && function_exists("mb_convert_encoding")) { $update = mb_convert_encoding($update, 'UTF-8', LANG_CHARSET); } if ($account_type == "identica"){ $api = new Twitter($account_type=='identica'); $twit = $api->update( $account_name, $account_pwd, $update ); } else { $connection = $this->twitteroa_connect($acc_number); $api = new TwitterOAuthApi($connection); $status = $api->update($update); $twit = true; } if ($twit === true){ $notice = PLUGIN_EVENT_TWITTER_TWEETER_STORED; } else{ $val_tweet = $_POST['tweet']; $notice = PLUGIN_EVENT_TWITTER_TWEETER_STOREFAIL . $twit; } } } } elseif (isset($_POST['tweeter_change_identity'])) { $val_tweet = $_POST['tweet']; $val_short = $_POST['shorturl']; } // Create strings of twitter URL length: $this->twitter_check_config(); $http_length_str = str_repeat("=", (int)$this->get_config('twitter_config_http_len')); $https_length_str = str_repeat("=", (int)$this->get_config('twitter_config_https_len')); // Hide shorten url input, if no url shorter is used! if ('raw' == $this->get_config('anounce_url_service','7ax.de')) { echo ""; @define('PLUGIN_EVENT_TWITTER_TWEETER_SHORTEN_OR_UPDATE', PLUGIN_EVENT_TWITTER_TWEETER_UPDATE); } else { @define('PLUGIN_EVENT_TWITTER_TWEETER_SHORTEN_OR_UPDATE', PLUGIN_EVENT_TWITTER_TWEETER_SHORTEN . ' / ' . PLUGIN_EVENT_TWITTER_TWEETER_UPDATE); } // Display the form include dirname(__FILE__) . '/tweeter/tweeter_client.inc.php'; } else { return true; // if disabled, don't display anything else! } // Display history if($tweeter_has_timeline){ if ($account_type == "identica"){ $count = $this->get_config('tweeter_history_count', 10); $api = new Twitter($account_type=='identica'); $statuses = $api->timeline( $account_name, $account_pwd, $count ); } else { require_once(dirname(__FILE__).'/twitteroauth/twitteroauth.php'); if ($_POST['tweeter_timeline']){ $get_connection = "statuses/".$_POST['tweeter_timeline']; } else { $get_connection = "statuses/".$this->get_config('tweeter_timeline'); } $connection = $this->twitteroa_connect($acc_number); $statuses = $connection->get($get_connection); $http_code = $connection->http_code; $api = new Twitter($account_type=='identica'); } $buffer = ''; if (!is_array($statuses)) { if (empty($statuses)) { $buffer = '
  • Result from Twitter was empty.
    Perhaps down for maintenance?
  • '; } elseif (is_object($statuses)) { if (!empty($statuses->error)) { $buffer = '
  • ' . $statuses->error . '
  • '; } else { $buffer = '
  • Reported an unknown error
  • '; } } else { print_r($statuses); $buffer = '
  • Twitter reported http error ' . $statuses . '
  • '; } } else { if ($account_type == "twitter"){ if ($_POST['tweeter_timeline']){ $buffer_header = PLUGIN_EVENT_TWITTER_TIMELINE.": ".$_POST['tweeter_timeline']; } else { $buffer_header = PLUGIN_EVENT_TWITTER_TIMELINE.": ".$this->get_config('tweeter_timeline'); } } foreach($statuses as $status){ // Setup links inside of the text $status->text = $api->replace_links_in_status($status->text); // Change encoding to blog encoding if (LANG_CHARSET!='UTF-8' && function_exists("mb_convert_encoding")) { $status->text = mb_convert_encoding($status->text, LANG_CHARSET, 'UTF-8'); } if (strtoupper($account_name)!=strtoupper($status->user->screen_name)) { $reply_link = '@'; $direct_link = 'DM'; $retweet_link = 'text))) . '\');" title="' . PLUGIN_EVENT_TWITTER_TWEETER_RETWEET . '">RT'; } else { $reply_link = ''; $direct_link = ''; $retweet_link = ''; } // Twitter delivers the complete status ID in an extra field! $status_id = $account_type=='identica'?$status->id:$status->id_str; // Add each status formatted to a html buffer $buffer .= '
  • '.$status->user->screen_name.' '.$status->text.'
  • '; } } // Display the history include dirname(__FILE__) . '/tweeter/tweeter_history.inc.php'; $return = true; } } // We generate a secret only known by the blog admit. // We use the directory of this plugin md5'd static function pluginSecret() { return md5(dirname(__FILE__)); } static function getTwitterOauths() { $idcount = serendipity_event_twitter::get_config_event('id_count'); if (empty($idcount)) { return array(); } $twitter_oauths = array(); for ($idx=1; $idx<=$idcount; $idx++) { $suffix = $idx==1?'':$idx; $service = serendipity_event_twitter::get_config_event('id_service' . $suffix); if ($service == "twitter") { $oautKey = serendipity_event_twitter::get_config_event('twitteroa_consumer_secret' . $suffix); if (!empty($oautKey)) { $twitter_oauths[$idx] = serendipity_event_twitter::get_config_event('twittername' . $suffix); } } } return $twitter_oauths; } static function get_config_event($name, $defaultvalue = null) { global $serendipity; $db_event_search = "serendipity_event_twitter:%/" . $name; $r = serendipity_db_query("SELECT value FROM {$serendipity['dbPrefix']}config WHERE name like '" . $db_event_search . "' LIMIT 1", true); if (is_array($r)) { return $r[0]; } else { return $defaultvalue; } } }