And one notice removed for twitter
[friendica-addons.git/.git] / twitter / twitter.php
index da103ae..8b71664 100644 (file)
  *     we do not need "Twitter as login". When you've registered the app you get the
  *     OAuth Consumer key and secret pair for your application/site.
  *
- *     Add this key pair to your global .htconfig.php or use the admin panel.
+ *     Add this key pair to your global config/addon.ini.php or use the admin panel.
  *
- *     $a->config['twitter']['consumerkey'] = 'your consumer_key here';
- *     $a->config['twitter']['consumersecret'] = 'your consumer_secret here';
+ *     [twitter]
+ *     consumerkey = your consumer_key here
+ *     consumersecret = your consumer_secret here
  *
- *     To activate the addon itself add it to the $a->config['system']['addon']
+ *     To activate the addon itself add it to the [system] addon
  *     setting. After this, your user can configure their Twitter account settings
  *     from "Settings -> Addon Settings".
  *
@@ -69,9 +70,12 @@ use Friendica\Core\Addon;
 use Friendica\Core\Config;
 use Friendica\Core\L10n;
 use Friendica\Core\PConfig;
+use Friendica\Core\Protocol;
 use Friendica\Core\Worker;
-use Friendica\Model\GContact;
+use Friendica\Database\DBA;
 use Friendica\Model\Contact;
+use Friendica\Model\Conversation;
+use Friendica\Model\GContact;
 use Friendica\Model\Group;
 use Friendica\Model\Item;
 use Friendica\Model\ItemContent;
@@ -80,7 +84,6 @@ use Friendica\Model\User;
 use Friendica\Object\Image;
 use Friendica\Util\DateTimeFormat;
 use Friendica\Util\Network;
-use Friendica\Database\DBM;
 
 require_once 'boot.php';
 require_once 'include/dba.php';
@@ -94,47 +97,54 @@ define('TWITTER_DEFAULT_POLL_INTERVAL', 5); // given in minutes
 function twitter_install()
 {
        //  we need some hooks, for the configuration and for sending tweets
-       Addon::registerHook('connector_settings', 'addon/twitter/twitter.php', 'twitter_settings');
-       Addon::registerHook('connector_settings_post', 'addon/twitter/twitter.php', 'twitter_settings_post');
-       Addon::registerHook('post_local', 'addon/twitter/twitter.php', 'twitter_post_local');
-       Addon::registerHook('notifier_normal', 'addon/twitter/twitter.php', 'twitter_post_hook');
-       Addon::registerHook('jot_networks', 'addon/twitter/twitter.php', 'twitter_jot_nets');
-       Addon::registerHook('cron', 'addon/twitter/twitter.php', 'twitter_cron');
-       Addon::registerHook('queue_predeliver', 'addon/twitter/twitter.php', 'twitter_queue_hook');
-       Addon::registerHook('follow', 'addon/twitter/twitter.php', 'twitter_follow');
-       Addon::registerHook('expire', 'addon/twitter/twitter.php', 'twitter_expire');
-       Addon::registerHook('prepare_body', 'addon/twitter/twitter.php', 'twitter_prepare_body');
-       Addon::registerHook('check_item_notification', 'addon/twitter/twitter.php', 'twitter_check_item_notification');
+       Addon::registerHook('load_config'            , __FILE__, 'twitter_load_config');
+       Addon::registerHook('connector_settings'     , __FILE__, 'twitter_settings');
+       Addon::registerHook('connector_settings_post', __FILE__, 'twitter_settings_post');
+       Addon::registerHook('post_local'             , __FILE__, 'twitter_post_local');
+       Addon::registerHook('notifier_normal'        , __FILE__, 'twitter_post_hook');
+       Addon::registerHook('jot_networks'           , __FILE__, 'twitter_jot_nets');
+       Addon::registerHook('cron'                   , __FILE__, 'twitter_cron');
+       Addon::registerHook('queue_predeliver'       , __FILE__, 'twitter_queue_hook');
+       Addon::registerHook('follow'                 , __FILE__, 'twitter_follow');
+       Addon::registerHook('expire'                 , __FILE__, 'twitter_expire');
+       Addon::registerHook('prepare_body'           , __FILE__, 'twitter_prepare_body');
+       Addon::registerHook('check_item_notification', __FILE__, 'twitter_check_item_notification');
        logger("installed twitter");
 }
 
 function twitter_uninstall()
 {
-       Addon::unregisterHook('connector_settings', 'addon/twitter/twitter.php', 'twitter_settings');
-       Addon::unregisterHook('connector_settings_post', 'addon/twitter/twitter.php', 'twitter_settings_post');
-       Addon::unregisterHook('post_local', 'addon/twitter/twitter.php', 'twitter_post_local');
-       Addon::unregisterHook('notifier_normal', 'addon/twitter/twitter.php', 'twitter_post_hook');
-       Addon::unregisterHook('jot_networks', 'addon/twitter/twitter.php', 'twitter_jot_nets');
-       Addon::unregisterHook('cron', 'addon/twitter/twitter.php', 'twitter_cron');
-       Addon::unregisterHook('queue_predeliver', 'addon/twitter/twitter.php', 'twitter_queue_hook');
-       Addon::unregisterHook('follow', 'addon/twitter/twitter.php', 'twitter_follow');
-       Addon::unregisterHook('expire', 'addon/twitter/twitter.php', 'twitter_expire');
-       Addon::unregisterHook('prepare_body', 'addon/twitter/twitter.php', 'twitter_prepare_body');
-       Addon::unregisterHook('check_item_notification', 'addon/twitter/twitter.php', 'twitter_check_item_notification');
+       Addon::unregisterHook('load_config'            , __FILE__, 'twitter_load_config');
+       Addon::unregisterHook('connector_settings'     , __FILE__, 'twitter_settings');
+       Addon::unregisterHook('connector_settings_post', __FILE__, 'twitter_settings_post');
+       Addon::unregisterHook('post_local'             , __FILE__, 'twitter_post_local');
+       Addon::unregisterHook('notifier_normal'        , __FILE__, 'twitter_post_hook');
+       Addon::unregisterHook('jot_networks'           , __FILE__, 'twitter_jot_nets');
+       Addon::unregisterHook('cron'                   , __FILE__, 'twitter_cron');
+       Addon::unregisterHook('queue_predeliver'       , __FILE__, 'twitter_queue_hook');
+       Addon::unregisterHook('follow'                 , __FILE__, 'twitter_follow');
+       Addon::unregisterHook('expire'                 , __FILE__, 'twitter_expire');
+       Addon::unregisterHook('prepare_body'           , __FILE__, 'twitter_prepare_body');
+       Addon::unregisterHook('check_item_notification', __FILE__, 'twitter_check_item_notification');
 
        // old setting - remove only
-       Addon::unregisterHook('post_local_end', 'addon/twitter/twitter.php', 'twitter_post_hook');
-       Addon::unregisterHook('addon_settings', 'addon/twitter/twitter.php', 'twitter_settings');
-       Addon::unregisterHook('addon_settings_post', 'addon/twitter/twitter.php', 'twitter_settings_post');
+       Addon::unregisterHook('post_local_end'     , __FILE__, 'twitter_post_hook');
+       Addon::unregisterHook('addon_settings'     , __FILE__, 'twitter_settings');
+       Addon::unregisterHook('addon_settings_post', __FILE__, 'twitter_settings_post');
+}
+
+function twitter_load_config(App $a)
+{
+       $a->loadConfigFile(__DIR__ . '/config/twitter.ini.php');
 }
 
-function twitter_check_item_notification(App $a, &$notification_data)
+function twitter_check_item_notification(App $a, array &$notification_data)
 {
        $own_id = PConfig::get($notification_data["uid"], 'twitter', 'own_id');
 
        $own_user = q("SELECT `url` FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
                        intval($notification_data["uid"]),
-                       dbesc("twitter::".$own_id)
+                       DBA::escape("twitter::".$own_id)
        );
 
        if ($own_user) {
@@ -142,7 +152,7 @@ function twitter_check_item_notification(App $a, &$notification_data)
        }
 }
 
-function twitter_follow(App $a, &$contact)
+function twitter_follow(App $a, array &$contact)
 {
        logger("twitter_follow: Check if contact is twitter contact. " . $contact["url"], LOGGER_DEBUG);
 
@@ -175,8 +185,8 @@ function twitter_follow(App $a, &$contact)
        $r = q("SELECT name,nick,url,addr,batch,notify,poll,request,confirm,poco,photo,priority,network,alias,pubkey
                FROM `contact` WHERE `uid` = %d AND `nick` = '%s'",
                                intval($uid),
-                               dbesc($nickname));
-       if (DBM::is_result($r)) {
+                               DBA::escape($nickname));
+       if (DBA::isResult($r)) {
                $contact["contact"] = $r[0];
        }
 }
@@ -196,7 +206,7 @@ function twitter_jot_nets(App $a, &$b)
        }
 }
 
-function twitter_settings_post(App $a, $post)
+function twitter_settings_post(App $a)
 {
        if (!local_user()) {
                return;
@@ -377,7 +387,7 @@ function twitter_settings(App $a, &$s)
        $s .= '</div><div class="clear"></div>';
 }
 
-function twitter_post_local(App $a, &$b)
+function twitter_post_local(App $a, array &$b)
 {
        if ($b['edit']) {
                return;
@@ -422,6 +432,7 @@ function twitter_action(App $a, $uid, $pid, $action)
        switch ($action) {
                case "delete":
                        // To-Do: $result = $connection->post('statuses/destroy', $post);
+                       $result = [];
                        break;
                case "like":
                        $result = $connection->post('favorites/create', $post);
@@ -429,11 +440,14 @@ function twitter_action(App $a, $uid, $pid, $action)
                case "unlike":
                        $result = $connection->post('favorites/destroy', $post);
                        break;
+               default:
+                       logger('Unhandled action ' . $action, LOGGER_DEBUG);
+                       $result = [];
        }
        logger("twitter_action '" . $action . "' send, result: " . print_r($result, true), LOGGER_DEBUG);
 }
 
-function twitter_post_hook(App $a, &$b)
+function twitter_post_hook(App $a, array &$b)
 {
        // Post to Twitter
        if (!PConfig::get($b["uid"], 'twitter', 'import')
@@ -453,16 +467,13 @@ function twitter_post_hook(App $a, &$b)
                        return;
                }
 
-               $r = q("SELECT * FROM item WHERE item.uri = '%s' AND item.uid = %d LIMIT 1",
-                       dbesc($b["thr-parent"]),
-                       intval($b["uid"]));
-
-               if (!DBM::is_result($r)) {
+               $condition = ['uri' => $b["thr-parent"], 'uid' => $b["uid"]];
+               $orig_post = Item::selectFirst([], $condition);
+               if (!DBA::isResult($orig_post)) {
                        logger("twitter_post_hook: no parent found " . $b["thr-parent"]);
                        return;
                } else {
                        $iscomment = true;
-                       $orig_post = $r[0];
                }
 
 
@@ -485,7 +496,7 @@ function twitter_post_hook(App $a, &$b)
 
                // Dont't post if the post doesn't belong to us.
                // This is a check for forum postings
-               $self = dba::selectFirst('contact', ['id'], ['uid' => $b['uid'], 'self' => true]);
+               $self = DBA::selectFirst('contact', ['id'], ['uid' => $b['uid'], 'self' => true]);
                if ($b['contact-id'] != $self['id']) {
                        return;
                }
@@ -511,7 +522,7 @@ function twitter_post_hook(App $a, &$b)
        }
 
        // if post comes from twitter don't send it back
-       if ($b['extid'] == NETWORK_TWITTER) {
+       if ($b['extid'] == Protocol::TWITTER) {
                return;
        }
 
@@ -604,21 +615,21 @@ function twitter_post_hook(App $a, &$b)
                $result = $connection->post($url, $post);
                logger('twitter_post send, result: ' . print_r($result, true), LOGGER_DEBUG);
 
-               if ($result->source) {
+               if (!empty($result->source)) {
                        Config::set("twitter", "application_name", strip_tags($result->source));
                }
 
-               if ($result->errors) {
+               if (!empty($result->errors)) {
                        logger('Send to Twitter failed: "' . print_r($result->errors, true) . '"');
 
                        $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `self`", intval($b['uid']));
-                       if (DBM::is_result($r)) {
+                       if (DBA::isResult($r)) {
                                $a->contact = $r[0]["id"];
                        }
 
                        $s = serialize(['url' => $url, 'item' => $b['id'], 'post' => $post]);
 
-                       Queue::add($a->contact, NETWORK_TWITTER, $s);
+                       Queue::add($a->contact, Protocol::TWITTER, $s);
                        notice(L10n::t('Twitter post failed. Queued for retry.') . EOL);
                } elseif ($iscomment) {
                        logger('twitter_post: Update extid ' . $result->id_str . " for post id " . $b['id']);
@@ -648,7 +659,7 @@ function twitter_addon_admin(App $a, &$o)
        ]);
 }
 
-function twitter_cron(App $a, $b)
+function twitter_cron(App $a)
 {
        $last = Config::get('twitter', 'last_poll');
 
@@ -667,7 +678,7 @@ function twitter_cron(App $a, $b)
        logger('twitter: cron_start');
 
        $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'mirror_posts' AND `v` = '1'");
-       if (DBM::is_result($r)) {
+       if (DBA::isResult($r)) {
                foreach ($r as $rr) {
                        logger('twitter: fetching for user ' . $rr['uid']);
                        Worker::add(PRIORITY_MEDIUM, "addon/twitter/twitter_sync.php", 1, (int) $rr['uid']);
@@ -682,11 +693,11 @@ function twitter_cron(App $a, $b)
        $abandon_limit = date(DateTimeFormat::MYSQL, time() - $abandon_days * 86400);
 
        $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'import' AND `v` = '1'");
-       if (DBM::is_result($r)) {
+       if (DBA::isResult($r)) {
                foreach ($r as $rr) {
                        if ($abandon_days != 0) {
                                $user = q("SELECT `login_date` FROM `user` WHERE uid=%d AND `login_date` >= '%s'", $rr['uid'], $abandon_limit);
-                               if (!DBM::is_result($user)) {
+                               if (!DBA::isResult($user)) {
                                        logger('abandoned account: timeline from user ' . $rr['uid'] . ' will not be imported');
                                        continue;
                                }
@@ -716,7 +727,7 @@ function twitter_cron(App $a, $b)
        Config::set('twitter', 'last_poll', time());
 }
 
-function twitter_expire(App $a, $b)
+function twitter_expire(App $a)
 {
        $days = Config::get('twitter', 'expire');
 
@@ -724,34 +735,30 @@ function twitter_expire(App $a, $b)
                return;
        }
 
-       if (method_exists('dba', 'delete')) {
-               $r = dba::select('item', ['id'], ['deleted' => true, 'network' => NETWORK_TWITTER]);
-               while ($row = dba::fetch($r)) {
-                       dba::delete('item', ['id' => $row['id']]);
-               }
-               dba::close($r);
-       } else {
-               $r = q("DELETE FROM `item` WHERE `deleted` AND `network` = '%s'", dbesc(NETWORK_TWITTER));
+       $r = Item::select(['id'], ['deleted' => true, 'network' => Protocol::TWITTER]);
+       while ($row = DBA::fetch($r)) {
+               DBA::delete('item', ['id' => $row['id']]);
        }
+       DBA::close($r);
 
        require_once "include/items.php";
 
        logger('twitter_expire: expire_start');
 
        $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'import' AND `v` = '1' ORDER BY RAND()");
-       if (DBM::is_result($r)) {
+       if (DBA::isResult($r)) {
                foreach ($r as $rr) {
                        logger('twitter_expire: user ' . $rr['uid']);
-                       Item::expire($rr['uid'], $days, NETWORK_TWITTER, true);
+                       Item::expire($rr['uid'], $days, Protocol::TWITTER, true);
                }
        }
 
        logger('twitter_expire: expire_end');
 }
 
-function twitter_prepare_body(App $a, &$b)
+function twitter_prepare_body(App $a, array &$b)
 {
-       if ($b["item"]["network"] != NETWORK_TWITTER) {
+       if ($b["item"]["network"] != Protocol::TWITTER) {
                return;
        }
 
@@ -760,13 +767,9 @@ function twitter_prepare_body(App $a, &$b)
                $item = $b["item"];
                $item["plink"] = $a->get_baseurl() . "/display/" . $a->user["nickname"] . "/" . $item["parent"];
 
-               $r = q("SELECT `author-link` FROM item WHERE item.uri = '%s' AND item.uid = %d LIMIT 1",
-                       dbesc($item["thr-parent"]),
-                       intval(local_user()));
-
-               if (DBM::is_result($r)) {
-                       $orig_post = $r[0];
-
+               $condition = ['uri' => $item["thr-parent"], 'uid' => local_user()];
+               $orig_post = Item::selectFirst(['author-link'], $condition);
+               if (DBA::isResult($orig_post)) {
                        $nicknameplain = preg_replace("=https?://twitter.com/(.*)=ism", "$1", $orig_post["author-link"]);
                        $nickname = "@[url=" . $orig_post["author-link"] . "]" . $nicknameplain . "[/url]";
                        $nicknameplain = "@" . $nicknameplain;
@@ -802,23 +805,27 @@ function twitter_prepare_body(App $a, &$b)
  */
 function twitter_do_mirrorpost(App $a, $uid, $post)
 {
-       $datarray["type"] = "wall";
-       $datarray["api_source"] = true;
-       $datarray["profile_uid"] = $uid;
-       $datarray["extid"] = NETWORK_TWITTER;
-       $datarray['message_id'] = item_new_uri($a->get_hostname(), $uid, NETWORK_TWITTER . ":" . $post->id);
-       $datarray['object'] = json_encode($post);
-       $datarray["title"] = "";
-
-       if (is_object($post->retweeted_status)) {
+       $datarray['api_source'] = true;
+       $datarray['profile_uid'] = $uid;
+       $datarray['extid'] = Protocol::TWITTER;
+       $datarray['message_id'] = Item::newURI($uid, Protocol::TWITTER . ':' . $post->id);
+       $datarray['protocol'] = Conversation::PARCEL_TWITTER;
+       $datarray['source'] = json_encode($post);
+       $datarray['title'] = '';
+
+       if (!empty($post->retweeted_status)) {
                // We don't support nested shares, so we mustn't show quotes as shares on retweets
                $item = twitter_createpost($a, $uid, $post->retweeted_status, ['id' => 0], false, false, true);
 
+               if (empty($item['body'])) {
+                       return [];
+               }
+
                $datarray['body'] = "\n" . share_header(
                        $item['author-name'],
                        $item['author-link'],
                        $item['author-avatar'],
-                       "",
+                       '',
                        $item['created'],
                        $item['plink']
                );
@@ -827,18 +834,22 @@ function twitter_do_mirrorpost(App $a, $uid, $post)
        } else {
                $item = twitter_createpost($a, $uid, $post, ['id' => 0], false, false, false);
 
+               if (empty($item['body'])) {
+                       return [];
+               }
+
                $datarray['body'] = $item['body'];
        }
 
-       $datarray["source"] = $item['app'];
-       $datarray["verb"] = $item['verb'];
+       $datarray['source'] = $item['app'];
+       $datarray['verb'] = $item['verb'];
 
-       if (isset($item["location"])) {
-               $datarray["location"] = $item["location"];
+       if (isset($item['location'])) {
+               $datarray['location'] = $item['location'];
        }
 
-       if (isset($item["coord"])) {
-               $datarray["coord"] = $item["coord"];
+       if (isset($item['coord'])) {
+               $datarray['coord'] = $item['coord'];
        }
 
        return $datarray;
@@ -904,6 +915,10 @@ function twitter_fetchtimeline(App $a, $uid)
 
                                $_REQUEST = twitter_do_mirrorpost($a, $uid, $post);
 
+                               if (empty($_REQUEST['body'])) {
+                                       continue;
+                               }
+
                                logger('twitter: posting for user ' . $uid);
 
                                item_post($a);
@@ -913,17 +928,17 @@ function twitter_fetchtimeline(App $a, $uid)
        PConfig::set($uid, 'twitter', 'lastid', $lastid);
 }
 
-function twitter_queue_hook(App $a, &$b)
+function twitter_queue_hook(App $a)
 {
        $qi = q("SELECT * FROM `queue` WHERE `network` = '%s'",
-               dbesc(NETWORK_TWITTER)
+               DBA::escape(Protocol::TWITTER)
        );
-       if (!DBM::is_result($qi)) {
+       if (!DBA::isResult($qi)) {
                return;
        }
 
        foreach ($qi as $x) {
-               if ($x['network'] !== NETWORK_TWITTER) {
+               if ($x['network'] !== Protocol::TWITTER) {
                        continue;
                }
 
@@ -933,7 +948,7 @@ function twitter_queue_hook(App $a, &$b)
                        WHERE `contact`.`self` = 1 AND `contact`.`id` = %d LIMIT 1",
                        intval($x['cid'])
                );
-               if (!DBM::is_result($r)) {
+               if (!DBA::isResult($r)) {
                        continue;
                }
 
@@ -987,7 +1002,7 @@ function twitter_fix_avatar($avatar)
 
 function twitter_fetch_contact($uid, $data, $create_user)
 {
-       if ($data->id_str == "") {
+       if (empty($data->id_str)) {
                return -1;
        }
 
@@ -995,46 +1010,46 @@ function twitter_fetch_contact($uid, $data, $create_user)
        $url = "https://twitter.com/" . $data->screen_name;
        $addr = $data->screen_name . "@twitter.com";
 
-       GContact::update(["url" => $url, "network" => NETWORK_TWITTER,
+       GContact::update(["url" => $url, "network" => Protocol::TWITTER,
                "photo" => $avatar, "hide" => true,
                "name" => $data->name, "nick" => $data->screen_name,
                "location" => $data->location, "about" => $data->description,
                "addr" => $addr, "generation" => 2]);
 
-       $fields = ['url' => $url, 'network' => NETWORK_TWITTER,
+       $fields = ['url' => $url, 'network' => Protocol::TWITTER,
                'name' => $data->name, 'nick' => $data->screen_name, 'addr' => $addr,
                 'location' => $data->location, 'about' => $data->description];
 
        $cid = Contact::getIdForURL($url, 0, true, $fields);
        if (!empty($cid)) {
-               dba::update('contact', $fields, ['id' => $cid]);
+               DBA::update('contact', $fields, ['id' => $cid]);
                Contact::updateAvatar($avatar, 0, $cid);
        }
 
-       $contact = dba::selectFirst('contact', [], ['uid' => $uid, 'alias' => "twitter::" . $data->id_str]);
-       if (!DBM::is_result($contact) && !$create_user) {
+       $contact = DBA::selectFirst('contact', [], ['uid' => $uid, 'alias' => "twitter::" . $data->id_str]);
+       if (!DBA::isResult($contact) && !$create_user) {
                return 0;
        }
 
-       if (!DBM::is_result($contact)) {
+       if (!DBA::isResult($contact)) {
                // create contact record
                $fields['uid'] = $uid;
                $fields['created'] = DateTimeFormat::utcNow();
                $fields['nurl'] = normalise_link($url);
                $fields['alias'] = 'twitter::' . $data->id_str;
                $fields['poll'] = 'twitter::' . $data->id_str;
-               $fields['rel'] = CONTACT_IS_FRIEND;
+               $fields['rel'] = Contact::FRIEND;
                $fields['priority'] = 1;
                $fields['writable'] = true;
                $fields['blocked'] = false;
                $fields['readonly'] = false;
                $fields['pending'] = false;
 
-               if (!dba::insert('contact', $fields)) {
+               if (!DBA::insert('contact', $fields)) {
                        return false;
                }
 
-               $contact_id = dba::lastInsertId();
+               $contact_id = DBA::lastInsertId();
 
                Group::addMember(User::getDefaultGroup($uid), $contact_id);
 
@@ -1059,7 +1074,7 @@ function twitter_fetch_contact($uid, $data, $create_user)
                        $fields['name-date'] = DateTimeFormat::utcNow();
                        $fields['uri-date'] = DateTimeFormat::utcNow();
 
-                       dba::update('contact', $fields, ['id' => $contact['id']]);
+                       DBA::update('contact', $fields, ['id' => $contact['id']]);
                }
        }
 
@@ -1076,7 +1091,7 @@ function twitter_fetchuser(App $a, $uid, $screen_name = "", $user_id = "")
        $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
                intval($uid));
 
-       if (DBM::is_result($r)) {
+       if (DBA::isResult($r)) {
                $self = $r[0];
        } else {
                return;
@@ -1142,6 +1157,10 @@ function twitter_expand_entities(App $a, $body, $item, $picture)
 
                                $oembed_data = OEmbed::fetchURL($expanded_url);
 
+                               if (empty($oembed_data) || empty($oembed_data->type)) {
+                                       continue;
+                               }
+
                                // Quickfix: Workaround for URL with "[" and "]" in it
                                if (strpos($expanded_url, "[") || strpos($expanded_url, "]")) {
                                        $expanded_url = $url->url;
@@ -1157,7 +1176,7 @@ function twitter_expand_entities(App $a, $body, $item, $picture)
                                        //$dontincludemedia = true;
                                        $type = $oembed_data->type;
                                        $footerurl = $expanded_url;
-                                       $footerlink = "[url=" . $expanded_url . "]" . $expanded_url . "[/url]";
+                                       $footerlink = "[url=" . $expanded_url . "]" . $url->display_url . "[/url]";
 
                                        $body = str_replace($url->url, $footerlink, $body);
                                        //} elseif (($oembed_data->type == "photo") AND isset($oembed_data->url) AND !$dontincludemedia) {
@@ -1165,13 +1184,20 @@ function twitter_expand_entities(App $a, $body, $item, $picture)
                                        $body = str_replace($url->url, "[url=" . $expanded_url . "][img]" . $oembed_data->url . "[/img][/url]", $body);
                                        //$dontincludemedia = true;
                                } elseif ($oembed_data->type != "link") {
-                                       $body = str_replace($url->url, "[url=" . $expanded_url . "]" . $expanded_url . "[/url]", $body);
+                                       $body = str_replace($url->url, "[url=" . $expanded_url . "]" . $url->display_url . "[/url]", $body);
                                } else {
                                        $img_str = Network::fetchUrl($expanded_url, true, $redirects, 4);
 
                                        $tempfile = tempnam(get_temppath(), "cache");
                                        file_put_contents($tempfile, $img_str);
-                                       $mime = image_type_to_mime_type(exif_imagetype($tempfile));
+
+                                       // See http://php.net/manual/en/function.exif-imagetype.php#79283
+                                       if (filesize($tempfile) > 11) {
+                                               $mime = image_type_to_mime_type(exif_imagetype($tempfile));
+                                       } else {
+                                               $mime = false;
+                                       }
+
                                        unlink($tempfile);
 
                                        if (substr($mime, 0, 6) == "image/") {
@@ -1181,7 +1207,7 @@ function twitter_expand_entities(App $a, $body, $item, $picture)
                                        } else {
                                                $type = $oembed_data->type;
                                                $footerurl = $expanded_url;
-                                               $footerlink = "[url=" . $expanded_url . "]" . $expanded_url . "[/url]";
+                                               $footerlink = "[url=" . $expanded_url . "]" . $url->display_url . "[/url]";
 
                                                $body = str_replace($url->url, $footerlink, $body);
                                        }
@@ -1262,10 +1288,10 @@ function twitter_expand_entities(App $a, $body, $item, $picture)
  *
  * @return $picture string Image URL or empty string
  */
-function twitter_media_entities($post, &$postarray)
+function twitter_media_entities($post, array &$postarray)
 {
        // There are no media entities? So we quit.
-       if (!is_array($post->extended_entities->media)) {
+       if (empty($post->extended_entities->media)) {
                return "";
        }
 
@@ -1285,6 +1311,9 @@ function twitter_media_entities($post, &$postarray)
        // This is a pure media post, first search for all media urls
        $media = [];
        foreach ($post->extended_entities->media AS $medium) {
+               if (!isset($media[$medium->url])) {
+                       $media[$medium->url] = '';
+               }
                switch ($medium->type) {
                        case 'photo':
                                $media[$medium->url] .= "\n[img]" . $medium->media_url_https . "[/img]";
@@ -1318,23 +1347,18 @@ function twitter_media_entities($post, &$postarray)
        return "";
 }
 
-function twitter_createpost(App $a, $uid, $post, $self, $create_user, $only_existing_contact, $noquote)
+function twitter_createpost(App $a, $uid, $post, array $self, $create_user, $only_existing_contact, $noquote)
 {
        $postarray = [];
-       $postarray['network'] = NETWORK_TWITTER;
-       $postarray['gravity'] = 0;
+       $postarray['network'] = Protocol::TWITTER;
        $postarray['uid'] = $uid;
        $postarray['wall'] = 0;
        $postarray['uri'] = "twitter::" . $post->id_str;
-       $postarray['object'] = json_encode($post);
+       $postarray['protocol'] = Conversation::PARCEL_TWITTER;
+       $postarray['source'] = json_encode($post);
 
        // Don't import our own comments
-       $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
-               dbesc($postarray['uri']),
-               intval($uid)
-       );
-
-       if (DBM::is_result($r)) {
+       if (Item::exists(['extid' => $postarray['uri'], 'uid' => $uid])) {
                logger("Item with extid " . $postarray['uri'] . " found.", LOGGER_DEBUG);
                return [];
        }
@@ -1344,30 +1368,21 @@ function twitter_createpost(App $a, $uid, $post, $self, $create_user, $only_exis
        if ($post->in_reply_to_status_id_str != "") {
                $parent = "twitter::" . $post->in_reply_to_status_id_str;
 
-               $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
-                       dbesc($parent),
-                       intval($uid)
-               );
-               if (DBM::is_result($r)) {
-                       $postarray['thr-parent'] = $r[0]["uri"];
-                       $postarray['parent-uri'] = $r[0]["parent-uri"];
-                       $postarray['parent'] = $r[0]["parent"];
+               $fields = ['uri', 'parent-uri', 'parent'];
+               $parent_item = Item::selectFirst($fields, ['uri' => $parent, 'uid' => $uid]);
+               if (!DBA::isResult($parent_item)) {
+                       $parent_item = Item::selectFirst($fields, ['extid' => $parent, 'uid' => $uid]);
+               }
+
+               if (DBA::isResult($parent_item)) {
+                       $postarray['thr-parent'] = $parent_item['uri'];
+                       $postarray['parent-uri'] = $parent_item['parent-uri'];
+                       $postarray['parent'] = $parent_item['parent'];
                        $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
                } else {
-                       $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
-                               dbesc($parent),
-                               intval($uid)
-                       );
-                       if (DBM::is_result($r)) {
-                               $postarray['thr-parent'] = $r[0]['uri'];
-                               $postarray['parent-uri'] = $r[0]['parent-uri'];
-                               $postarray['parent'] = $r[0]['parent'];
-                               $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
-                       } else {
-                               $postarray['thr-parent'] = $postarray['uri'];
-                               $postarray['parent-uri'] = $postarray['uri'];
-                               $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
-                       }
+                       $postarray['thr-parent'] = $postarray['uri'];
+                       $postarray['parent-uri'] = $postarray['uri'];
+                       $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
                }
 
                // Is it me?
@@ -1377,7 +1392,7 @@ function twitter_createpost(App $a, $uid, $post, $self, $create_user, $only_exis
                        $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
                                intval($uid));
 
-                       if (DBM::is_result($r)) {
+                       if (DBA::isResult($r)) {
                                $contactid = $r[0]["id"];
 
                                $postarray['owner-name']   = $r[0]["name"];
@@ -1422,6 +1437,9 @@ function twitter_createpost(App $a, $uid, $post, $self, $create_user, $only_exis
        if ($post->user->protected) {
                $postarray['private'] = 1;
                $postarray['allow_cid'] = '<' . $self['id'] . '>';
+       } else {
+               $postarray['private'] = 0;
+               $postarray['allow_cid'] = '';
        }
 
        if (is_string($post->full_text)) {
@@ -1446,22 +1464,26 @@ function twitter_createpost(App $a, $uid, $post, $self, $create_user, $only_exis
 
        $statustext = $converted["plain"];
 
-       if (is_string($post->place->name)) {
+       if (!empty($post->place->name)) {
                $postarray["location"] = $post->place->name;
        }
-       if (is_string($post->place->full_name)) {
+       if (!empty($post->place->full_name)) {
                $postarray["location"] = $post->place->full_name;
        }
-       if (is_array($post->geo->coordinates)) {
+       if (!empty($post->geo->coordinates)) {
                $postarray["coord"] = $post->geo->coordinates[0] . " " . $post->geo->coordinates[1];
        }
-       if (is_array($post->coordinates->coordinates)) {
+       if (!empty($post->coordinates->coordinates)) {
                $postarray["coord"] = $post->coordinates->coordinates[1] . " " . $post->coordinates->coordinates[0];
        }
-       if (is_object($post->retweeted_status)) {
+       if (!empty($post->retweeted_status)) {
                $retweet = twitter_createpost($a, $uid, $post->retweeted_status, $self, false, false, $noquote);
 
-               $retweet['object'] = $postarray['object'];
+               if (empty($retweet['body'])) {
+                       return [];
+               }
+
+               $retweet['source'] = $postarray['source'];
                $retweet['private'] = $postarray['private'];
                $retweet['allow_cid'] = $postarray['allow_cid'];
                $retweet['contact-id'] = $postarray['contact-id'];
@@ -1472,9 +1494,13 @@ function twitter_createpost(App $a, $uid, $post, $self, $create_user, $only_exis
                $postarray = $retweet;
        }
 
-       if (is_object($post->quoted_status) && !$noquote) {
+       if (!empty($post->quoted_status) && !$noquote) {
                $quoted = twitter_createpost($a, $uid, $post->quoted_status, $self, false, false, true);
 
+               if (empty($quoted['body'])) {
+                       return [];
+               }
+
                $postarray['body'] = $statustext;
 
                $postarray['body'] .= "\n" . share_header(
@@ -1492,82 +1518,13 @@ function twitter_createpost(App $a, $uid, $post, $self, $create_user, $only_exis
        return $postarray;
 }
 
-function twitter_checknotification(App $a, $uid, $own_id, $top_item, $postarray)
-{
-       /// TODO: this whole function doesn't seem to work. Needs complete check
-       $user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1",
-               intval($uid)
-       );
-
-       if (!DBM::is_result($user)) {
-               return;
-       }
-
-       // Is it me?
-       if (link_compare($user[0]["url"], $postarray['author-link'])) {
-               return;
-       }
-
-       $own_user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
-               intval($uid),
-               dbesc("twitter::".$own_id)
-       );
-
-       if (!DBM::is_result($own_user)) {
-               return;
-       }
-
-       // Is it me from twitter?
-       if (link_compare($own_user[0]["url"], $postarray['author-link'])) {
-               return;
-       }
-
-       $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0",
-               dbesc($postarray['parent-uri']),
-               intval($uid)
-       );
-
-       if (DBM::is_result($myconv)) {
-               foreach ($myconv as $conv) {
-                       // now if we find a match, it means we're in this conversation
-                       if (!link_compare($conv['author-link'], $user[0]["url"]) && !link_compare($conv['author-link'], $own_user[0]["url"])) {
-                               continue;
-                       }
-
-                       require_once 'include/enotify.php';
-
-                       $conv_parent = $conv['parent'];
-
-                       notification([
-                               'type' => NOTIFY_COMMENT,
-                               'notify_flags' => $user[0]['notify-flags'],
-                               'language' => $user[0]['language'],
-                               'to_name' => $user[0]['username'],
-                               'to_email' => $user[0]['email'],
-                               'uid' => $user[0]['uid'],
-                               'item' => $postarray,
-                               'link' => $a->get_baseurl() . '/display/' . urlencode(Item::getGuidById($top_item)),
-                               'source_name' => $postarray['author-name'],
-                               'source_link' => $postarray['author-link'],
-                               'source_photo' => $postarray['author-avatar'],
-                               'verb' => ACTIVITY_POST,
-                               'otype' => 'item',
-                               'parent' => $conv_parent,
-                       ]);
-
-                       // only send one notification
-                       break;
-               }
-       }
-}
-
-function twitter_fetchparentposts(App $a, $uid, $post, TwitterOAuth $connection, $self, $own_id)
+function twitter_fetchparentposts(App $a, $uid, $post, TwitterOAuth $connection, array $self)
 {
        logger("twitter_fetchparentposts: Fetching for user " . $uid . " and post " . $post->id_str, LOGGER_DEBUG);
 
        $posts = [];
 
-       while ($post->in_reply_to_status_id_str != "") {
+       while (!empty($post->in_reply_to_status_id_str)) {
                $parameters = ["trim_user" => false, "tweet_mode" => "extended", "id" => $post->in_reply_to_status_id_str];
 
                try {
@@ -1582,12 +1539,12 @@ function twitter_fetchparentposts(App $a, $uid, $post, TwitterOAuth $connection,
                        break;
                }
 
-               $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
-                       dbesc("twitter::".$post->id_str),
-                       intval($uid)
-               );
+               if (empty($post->id_str)) {
+                       logger("twitter_fetchparentposts: This is not a post " . json_encode($post), LOGGER_DEBUG);
+                       break;
+               }
 
-               if (DBM::is_result($r)) {
+               if (Item::exists(['uri' => 'twitter::' . $post->id_str, 'uid' => $uid])) {
                        break;
                }
 
@@ -1598,27 +1555,19 @@ function twitter_fetchparentposts(App $a, $uid, $post, TwitterOAuth $connection,
 
        $posts = array_reverse($posts);
 
-       if (count($posts)) {
+       if (!empty($posts)) {
                foreach ($posts as $post) {
                        $postarray = twitter_createpost($a, $uid, $post, $self, false, false, false);
 
-                       if (trim($postarray['body']) == "") {
+                       if (empty($postarray['body'])) {
                                continue;
                        }
 
                        $item = Item::insert($postarray);
 
-                       if ($notify) {
-                               $item = $notify;
-                       }
-
                        $postarray["id"] = $item;
 
                        logger('twitter_fetchparentpost: User ' . $self["nick"] . ' posted parent timeline item ' . $item);
-
-                       if ($item && !function_exists("check_item_notification")) {
-                               twitter_checknotification($a, $uid, $own_id, $item, $postarray);
-                       }
                }
        }
 }
@@ -1655,7 +1604,7 @@ function twitter_fetchhometimeline(App $a, $uid)
                intval($own_contact),
                intval($uid));
 
-       if (DBM::is_result($r)) {
+       if (DBA::isResult($r)) {
                $own_id = $r[0]["nick"];
        } else {
                logger("twitter_fetchhometimeline: Own twitter contact not found for user " . $uid, LOGGER_DEBUG);
@@ -1665,7 +1614,7 @@ function twitter_fetchhometimeline(App $a, $uid)
        $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
                intval($uid));
 
-       if (DBM::is_result($r)) {
+       if (DBA::isResult($r)) {
                $self = $r[0];
        } else {
                logger("twitter_fetchhometimeline: Own contact not found for user " . $uid, LOGGER_DEBUG);
@@ -1674,7 +1623,7 @@ function twitter_fetchhometimeline(App $a, $uid)
 
        $u = q("SELECT * FROM user WHERE uid = %d LIMIT 1",
                intval($uid));
-       if (!DBM::is_result($u)) {
+       if (!DBA::isResult($u)) {
                logger("twitter_fetchhometimeline: Own user not found for user " . $uid, LOGGER_DEBUG);
                return;
        }
@@ -1728,20 +1677,20 @@ function twitter_fetchhometimeline(App $a, $uid)
                        }
 
                        if ($post->in_reply_to_status_id_str != "") {
-                               twitter_fetchparentposts($a, $uid, $post, $connection, $self, $own_id);
+                               twitter_fetchparentposts($a, $uid, $post, $connection, $self);
                        }
 
                        $postarray = twitter_createpost($a, $uid, $post, $self, $create_user, true, false);
 
-                       if (trim($postarray['body']) == "") {
+                       if (empty($postarray['body']) || trim($postarray['body']) == "") {
                                continue;
                        }
 
                        $notify = false;
 
-                       if ($postarray['uri'] == $postarray['parent-uri']) {
-                               $contact = dba::selectFirst('contact', [], ['id' => $postarray['contact-id'], 'self' => false]);
-                               if (DBM::is_result($contact)) {
+                       if (($postarray['uri'] == $postarray['parent-uri']) && ($postarray['author-link'] == $postarray['owner-link'])) {
+                               $contact = DBA::selectFirst('contact', [], ['id' => $postarray['contact-id'], 'self' => false]);
+                               if (DBA::isResult($contact)) {
                                        $notify = Item::isRemoteSelf($contact, $postarray);
                                }
                        }
@@ -1750,10 +1699,6 @@ function twitter_fetchhometimeline(App $a, $uid)
                        $postarray["id"] = $item;
 
                        logger('twitter_fetchhometimeline: User ' . $self["nick"] . ' posted home timeline item ' . $item);
-
-                       if ($item && !function_exists("check_item_notification")) {
-                               twitter_checknotification($a, $uid, $own_id, $item, $postarray);
-                       }
                }
        }
        PConfig::set($uid, 'twitter', 'lasthometimelineid', $lastid);
@@ -1794,60 +1739,18 @@ function twitter_fetchhometimeline(App $a, $uid)
                        }
 
                        if ($post->in_reply_to_status_id_str != "") {
-                               twitter_fetchparentposts($a, $uid, $post, $connection, $self, $own_id);
+                               twitter_fetchparentposts($a, $uid, $post, $connection, $self);
                        }
 
                        $postarray = twitter_createpost($a, $uid, $post, $self, false, false, false);
 
-                       if (trim($postarray['body']) == "") {
+                       if (empty($postarray['body'])) {
                                continue;
                        }
 
                        $item = Item::insert($postarray);
-                       $postarray["id"] = $item;
-
-                       if ($item && function_exists("check_item_notification")) {
-                               check_item_notification($item, $uid, NOTIFY_TAGSELF);
-                       }
-
-                       if (!isset($postarray["parent"]) || ($postarray["parent"] == 0)) {
-                               $postarray["parent"] = $item;
-                       }
 
                        logger('twitter_fetchhometimeline: User ' . $self["nick"] . ' posted mention timeline item ' . $item);
-
-                       if ($item == 0) {
-                               $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
-                                       dbesc($postarray['uri']),
-                                       intval($uid)
-                               );
-                               if (DBM::is_result($r)) {
-                                       $item = $r[0]['id'];
-                                       $parent_id = $r[0]['parent'];
-                               }
-                       } else {
-                               $parent_id = $postarray['parent'];
-                       }
-
-                       if (($item != 0) && !function_exists("check_item_notification")) {
-                               require_once 'include/enotify.php';
-                               notification([
-                                       'type'         => NOTIFY_TAGSELF,
-                                       'notify_flags' => $u[0]['notify-flags'],
-                                       'language'     => $u[0]['language'],
-                                       'to_name'      => $u[0]['username'],
-                                       'to_email'     => $u[0]['email'],
-                                       'uid'          => $u[0]['uid'],
-                                       'item'         => $postarray,
-                                       'link'         => $a->get_baseurl() . '/display/' . urlencode(Item::getGuidById($item)),
-                                       'source_name'  => $postarray['author-name'],
-                                       'source_link'  => $postarray['author-link'],
-                                       'source_photo' => $postarray['author-avatar'],
-                                       'verb'         => ACTIVITY_TAG,
-                                       'otype'        => 'item',
-                                       'parent'       => $parent_id
-                               ]);
-                       }
                }
        }
 
@@ -1878,8 +1781,8 @@ function twitter_fetch_own_contact(App $a, $uid)
        } else {
                $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
                        intval($uid),
-                       dbesc("twitter::" . $own_id));
-               if (DBM::is_result($r)) {
+                       DBA::escape("twitter::" . $own_id));
+               if (DBA::isResult($r)) {
                        $contact_id = $r[0]["id"];
                } else {
                        PConfig::delete($uid, 'twitter', 'own_id');
@@ -1912,12 +1815,12 @@ function twitter_is_retweet(App $a, $uid, $body)
 
        $link = "";
        preg_match("/link='(.*?)'/ism", $attributes, $matches);
-       if ($matches[1] != "") {
+       if (!empty($matches[1])) {
                $link = $matches[1];
        }
 
        preg_match('/link="(.*?)"/ism', $attributes, $matches);
-       if ($matches[1] != "") {
+       if (!empty($matches[1])) {
                $link = $matches[1];
        }