]> git.mxchange.org Git - friendica.git/blobdiff - include/api.php
reformat todo according to doxygen style
[friendica.git] / include / api.php
index cf75428a3d12fa7c3d09d93b466534380df85f8f..70022067293a556413b4939dfc079f9dc15d4835 100644 (file)
@@ -1,7 +1,30 @@
 <?php
-/* To-Do:
- - Automatically detect if incoming data is HTML or BBCode
-*/
+/**
+ * @file include/api.php
+ * 
+ * @todo Automatically detect if incoming data is HTML or BBCode
+ */
+
+/* Contact details:
+       Gerhard Seeber          Mail: gerhard@seeber.at         Friendica: http://mozartweg.dyndns.org/friendica/gerhard
+
+ */
+
+
+/*
+ * Change history:
+       Gerhard Seeber          2015-NOV-25     Add API call /friendica/group_show to return all or a single group
+                                               with the containing contacts (necessary for Windows 10 Universal app)
+       Gerhard Seeber          2015-NOV-27     Add API call /friendica/group_delete to delete the specified group id
+                                               (necessary for Windows 10 Universal app)
+       Gerhard Seeber          2015-DEC-01     Add API call /friendica/group_create to create a group with the specified 
+                                               name and the given list of contacts (necessary for Windows 10 Universal
+                                               app)
+       Gerhard Seeber          2015-DEC-07     Add API call /friendica/group_update to update a group with the given 
+                                               list of contacts (necessary for Windows 10 Universal app)
+ *
+ */
+
        require_once("include/bbcode.php");
        require_once("include/datetime.php");
        require_once("include/conversation.php");
@@ -9,6 +32,15 @@
        require_once("include/html2plain.php");
        require_once("mod/share.php");
        require_once("include/Photo.php");
+       require_once("mod/item.php");
+       require_once('include/security.php');
+       require_once('include/contact_selectors.php');
+       require_once('include/html2bbcode.php');
+       require_once('mod/wall_upload.php');
+       require_once("mod/proxy.php");
+       require_once("include/message.php");
+       require_once("include/group.php");
+
 
        /*
         * Twitter-Like API
                $password = $_SERVER['PHP_AUTH_PW'];
                $encrypted = hash('whirlpool',trim($password));
 
+               // allow "user@server" login (but ignore 'server' part)
+               $at=strstr($user, "@", true);
+               if ( $at ) $user=$at;
 
                /**
                 *  next code from mod/auth.php. needs better solution
                $record = null;
 
                $addon_auth = array(
-                       'username' => trim($user), 
+                       'username' => trim($user),
                        'password' => trim($password),
                        'authenticated' => 0,
                        'user_record' => null
                        die('This api requires login');
                }
 
-               require_once('include/security.php');
                authenticate_success($record); $_SESSION["allow_api"] = true;
 
                call_hooks('logged_in', $a->user);
                                if (strpos($a->query_string, ".atom")>0) $type="atom";
                                if (strpos($a->query_string, ".as")>0) $type="as";
 
+                               $stamp =  microtime(true);
                                $r = call_user_func($info['func'], $a, $type);
+                               $duration = (float)(microtime(true)-$stamp);
+                               logger("API call duration: ".round($duration, 2)."\t".$a->query_string, LOGGER_DEBUG);
+
                                if ($r===false) return;
 
                                switch($type){
        }
 
        function api_error(&$a, $type, $error) {
-               # TODO:  https://dev.twitter.com/overview/api/response-codes
+               /// @TODO  https://dev.twitter.com/overview/api/response-codes
                $r = "<status><error>".$error."</error><request>".$a->query_string."</request></status>";
                switch($type){
                        case "xml":
         * Unique contact to contact url.
         */
        function api_unique_id_to_url($id){
-               $r = q("SELECT url FROM unique_contacts WHERE id=%d LIMIT 1",
+               $r = q("SELECT `url` FROM `unique_contacts` WHERE `id`=%d LIMIT 1",
                        intval($id));
                if ($r)
                        return ($r[0]["url"]);
                        $r = array();
 
                        if ($url != "")
-                               $r = q("SELECT * FROM unique_contacts WHERE url='%s' LIMIT 1", $url);
+                               $r = q("SELECT * FROM `unique_contacts` WHERE `url`='%s' LIMIT 1", $url);
                        elseif ($nick != "")
-                               $r = q("SELECT * FROM unique_contacts WHERE nick='%s' LIMIT 1", $nick);
+                               $r = q("SELECT * FROM `unique_contacts` WHERE `nick`='%s' LIMIT 1", $nick);
 
                        if ($r) {
                                // If no nick where given, extract it from the address
                                        'screen_name' => (($r[0]['nick']) ? $r[0]['nick'] : $r[0]['name']),
                                        'location' => NULL,
                                        'description' => NULL,
-                                       'profile_image_url' => $r[0]["avatar"],
-                                       'profile_image_url_https' => $r[0]["avatar"],
                                        'url' => $r[0]["url"],
                                        'protected' => false,
                                        'followers_count' => 0,
                                        'friends_count' => 0,
+                                       'listed_count' => 0,
                                        'created_at' => api_date(0),
                                        'favourites_count' => 0,
                                        'utc_offset' => 0,
                                        'time_zone' => 'UTC',
+                                       'geo_enabled' => false,
+                                       'verified' => false,
                                        'statuses_count' => 0,
+                                       'lang' => '',
+                                       'contributors_enabled' => false,
+                                       'is_translator' => false,
+                                       'is_translation_enabled' => false,
+                                       'profile_image_url' => $r[0]["avatar"],
+                                       'profile_image_url_https' => $r[0]["avatar"],
                                        'following' => false,
-                                       'verified' => false,
+                                       'follow_request_sent' => false,
+                                       'notifications' => false,
                                        'statusnet_blocking' => false,
                                        'notifications' => false,
                                        'statusnet_profile_url' => $r[0]["url"],
                }
 
                // Fetching unique id
-               $r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1", dbesc(normalise_link($uinfo[0]['url'])));
+               $r = q("SELECT id FROM `unique_contacts` WHERE `url`='%s' LIMIT 1", dbesc(normalise_link($uinfo[0]['url'])));
 
                // If not there, then add it
                if (count($r) == 0) {
-                       q("INSERT INTO unique_contacts (url, name, nick, avatar) VALUES ('%s', '%s', '%s', '%s')",
+                       q("INSERT INTO `unique_contacts` (`url`, `name`, `nick`, `avatar`) VALUES ('%s', '%s', '%s', '%s')",
                                dbesc(normalise_link($uinfo[0]['url'])), dbesc($uinfo[0]['name']),dbesc($uinfo[0]['nick']), dbesc($uinfo[0]['micro']));
 
-                       $r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1", dbesc(normalise_link($uinfo[0]['url'])));
+                       $r = q("SELECT `id` FROM `unique_contacts` WHERE `url`='%s' LIMIT 1", dbesc(normalise_link($uinfo[0]['url'])));
                }
 
-               require_once('include/contact_selectors.php');
-               $network_name = network_to_name($uinfo[0]['network']);
+               $network_name = network_to_name($uinfo[0]['network'], $uinfo[0]['url']);
 
                $ret = Array(
                        'id' => intval($r[0]['id']),
                        'verified' => true,
                        'statusnet_blocking' => false,
                        'notifications' => false,
-                       'statusnet_profile_url' => $a->get_baseurl()."/contacts/".$uinfo[0]['cid'],
+                       //'statusnet_profile_url' => $a->get_baseurl()."/contacts/".$uinfo[0]['cid'],
+                       'statusnet_profile_url' => $uinfo[0]['url'],
                        'uid' => intval($uinfo[0]['uid']),
                        'cid' => intval($uinfo[0]['cid']),
                        'self' => $uinfo[0]['self'],
 
        function api_item_get_user(&$a, $item) {
 
-               $author = q("SELECT * FROM unique_contacts WHERE url='%s' LIMIT 1",
+               $author = q("SELECT * FROM `unique_contacts` WHERE `url`='%s' LIMIT 1",
                        dbesc(normalise_link($item['author-link'])));
 
                if (count($author) == 0) {
-                       q("INSERT INTO unique_contacts (url, name, avatar) VALUES ('%s', '%s', '%s')",
-                       dbesc(normalise_link($item["author-link"])), dbesc($item["author-name"]), dbesc($item["author-avatar"]));
+                       q("INSERT INTO `unique_contacts` (`url`, `name`, `avatar`) VALUES ('%s', '%s', '%s')",
+                               dbesc(normalise_link($item["author-link"])), dbesc($item["author-name"]), dbesc($item["author-avatar"]));
 
-                       $author = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
+                       $author = q("SELECT `id` FROM `unique_contacts` WHERE `url`='%s' LIMIT 1",
                                dbesc(normalise_link($item['author-link'])));
                } else if ($item["author-link"].$item["author-name"] != $author[0]["url"].$author[0]["name"]) {
-                       q("UPDATE unique_contacts SET name = '%s', avatar = '%s' WHERE url = '%s'",
-                       dbesc($item["author-name"]), dbesc($item["author-avatar"]), dbesc(normalise_link($item["author-link"])));
+                       $r = q("SELECT `id` FROM `unique_contacts` WHERE `name` = '%s' AND `avatar` = '%s' AND url = '%s'",
+                               dbesc($item["author-name"]), dbesc($item["author-avatar"]),
+                               dbesc(normalise_link($item["author-link"])));
+
+                       if (!$r)
+                               q("UPDATE `unique_contacts` SET `name` = '%s', `avatar` = '%s' WHERE `url` = '%s'",
+                                       dbesc($item["author-name"]), dbesc($item["author-avatar"]),
+                                       dbesc(normalise_link($item["author-link"])));
                }
 
-               $owner = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
+               $owner = q("SELECT `id` FROM `unique_contacts` WHERE `url`='%s' LIMIT 1",
                        dbesc(normalise_link($item['owner-link'])));
 
                if (count($owner) == 0) {
-                       q("INSERT INTO unique_contacts (url, name, avatar) VALUES ('%s', '%s', '%s')",
-                       dbesc(normalise_link($item["owner-link"])), dbesc($item["owner-name"]), dbesc($item["owner-avatar"]));
+                       q("INSERT INTO `unique_contacts` (`url`, `name`, `avatar`) VALUES ('%s', '%s', '%s')",
+                               dbesc(normalise_link($item["owner-link"])), dbesc($item["owner-name"]), dbesc($item["owner-avatar"]));
 
-                       $owner = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
+                       $owner = q("SELECT `id` FROM `unique_contacts` WHERE `url`='%s' LIMIT 1",
                                dbesc(normalise_link($item['owner-link'])));
                } else if ($item["owner-link"].$item["owner-name"] != $owner[0]["url"].$owner[0]["name"]) {
-                       q("UPDATE unique_contacts SET name = '%s', avatar = '%s' WHERE url = '%s'",
-                       dbesc($item["owner-name"]), dbesc($item["owner-avatar"]), dbesc(normalise_link($item["owner-link"])));
+                       $r = q("SELECT `id` FROM `unique_contacts` WHERE `name` = '%s' AND `avatar` = '%s' AND url = '%s'",
+                               dbesc($item["owner-name"]), dbesc($item["owner-avatar"]),
+                               dbesc(normalise_link($item["owner-link"])));
+
+                       if (!$r)
+                               q("UPDATE `unique_contacts` SET `name` = '%s', `avatar` = '%s' WHERE `url` = '%s'",
+                                       dbesc($item["owner-name"]), dbesc($item["owner-avatar"]),
+                                       dbesc(normalise_link($item["owner-link"])));
                }
 
                // Comments in threads may appear as wall-to-wall postings.
                $txt = requestdata('status');
                //$txt = urldecode(requestdata('status'));
 
-               require_once('library/HTMLPurifier.auto.php');
-               require_once('include/html2bbcode.php');
-
                if((strpos($txt,'<') !== false) || (strpos($txt,'>') !== false)) {
+
+                       require_once('library/HTMLPurifier.auto.php');
+
                        $txt = html2bb_video($txt);
                        $config = HTMLPurifier_Config::createDefault();
                        $config->set('Cache.DefinitionImpl', null);
                $a->argv[1]=$user_info['screen_name']; //should be set to username?
 
                $_REQUEST['hush']='yeah'; //tell wall_upload function to return img info instead of echo
-               require_once('mod/wall_upload.php');
                $bebop = wall_upload_post($a);
 
                //now that we have the img url in bbcode we can add it to the status and insert the wall item.
                $_REQUEST['body']=$txt."\n\n".$bebop;
-               require_once('mod/item.php');
                item_post($a);
 
                // this should output the last post (the one we just posted).
                // logger('api_post: ' . print_r($_POST,true));
 
                if(requestdata('htmlstatus')) {
-                       require_once('library/HTMLPurifier.auto.php');
-                       require_once('include/html2bbcode.php');
-
                        $txt = requestdata('htmlstatus');
                        if((strpos($txt,'<') !== false) || (strpos($txt,'>') !== false)) {
 
+                               require_once('library/HTMLPurifier.auto.php');
+
                                $txt = html2bb_video($txt);
 
                                $config = HTMLPurifier_Config::createDefault();
                                $config->set('Cache.DefinitionImpl', null);
 
-
                                $purifier = new HTMLPurifier($config);
                                $txt = $purifier->purify($txt);
 
                $_REQUEST['title'] = requestdata('title');
 
                $parent = requestdata('in_reply_to_status_id');
+
+               // Twidere sends "-1" if it is no reply ...
+               if ($parent == -1)
+                       $parent = "";
+
                if(ctype_digit($parent))
                        $_REQUEST['parent'] = $parent;
                else
                if(x($_FILES,'media')) {
                        // upload the image if we have one
                        $_REQUEST['hush']='yeah'; //tell wall_upload function to return img info instead of echo
-                       require_once('mod/wall_upload.php');
                        $media = wall_upload_post($a);
                        if(strlen($media)>0)
                                $_REQUEST['body'] .= "\n\n".$media;
                }
 
-               // To-Do: Multiple IDs
+               /// @TODO Multiple IDs
                if (requestdata('media_ids')) {
                        $r = q("SELECT `resource-id`, `scale`, `nickname`, `type` FROM `photo` INNER JOIN `user` ON `user`.`uid` = `photo`.`uid` WHERE `resource-id` IN (SELECT `resource-id` FROM `photo` WHERE `id` = %d) AND `scale` > 0 AND `photo`.`uid` = %d ORDER BY `photo`.`width` DESC LIMIT 1",
                                intval(requestdata('media_ids')), api_user());
 
                // call out normal post function
 
-               require_once('mod/item.php');
                item_post($a);
 
                // this should output the last post (the one we just posted).
                        return false;
                }
 
-               require_once('mod/wall_upload.php');
                $media = wall_upload_post($a, false);
                if(!$media) {
                        // Output error
 
                logger('api_status_show: user_info: '.print_r($user_info, true), LOGGER_DEBUG);
 
+               if ($type == "raw")
+                       $privacy_sql = "AND `item`.`allow_cid`='' AND `item`.`allow_gid`='' AND `item`.`deny_cid`='' AND `item`.`deny_gid`=''";
+               else
+                       $privacy_sql = "";
+
                // get last public wall message
                $lastwall = q("SELECT `item`.*, `i`.`contact-id` as `reply_uid`, `i`.`author-link` AS `item-author`
                                FROM `item`, `item` as `i`
                                WHERE `item`.`contact-id` = %d AND `item`.`uid` = %d
                                        AND ((`item`.`author-link` IN ('%s', '%s')) OR (`item`.`owner-link` IN ('%s', '%s')))
                                        AND `i`.`id` = `item`.`parent`
-                                       AND `item`.`type`!='activity'
-                                       AND `item`.`allow_cid`='' AND `item`.`allow_gid`='' AND `item`.`deny_cid`='' AND `item`.`deny_gid`=''
+                                       AND `item`.`type`!='activity' $privacy_sql
                                ORDER BY `item`.`created` DESC
                                LIMIT 1",
                                intval($user_info['cid']),
                                $in_reply_to_status_id= intval($lastwall['parent']);
                                $in_reply_to_status_id_str = (string) intval($lastwall['parent']);
 
-                               $r = q("SELECT * FROM unique_contacts WHERE `url` = '%s'", dbesc(normalise_link($lastwall['item-author'])));
+                               $r = q("SELECT * FROM `unique_contacts` WHERE `url` = '%s'", dbesc(normalise_link($lastwall['item-author'])));
                                if ($r) {
                                        if ($r[0]['nick'] == "")
                                                $r[0]['nick'] = api_get_nick($r[0]["url"]);
                                $in_reply_to_screen_name = NULL;
                        }
 
-                       $converted = api_convert_item($item);
+                       $converted = api_convert_item($lastwall);
 
                        $status_info = array(
+                               'created_at' => api_date($lastwall['created']),
+                               'id' => intval($lastwall['id']),
+                               'id_str' => (string) $lastwall['id'],
                                'text' => $converted["text"],
+                               'source' => (($lastwall['app']) ? $lastwall['app'] : 'web'),
                                'truncated' => false,
-                               'created_at' => api_date($lastwall['created']),
                                'in_reply_to_status_id' => $in_reply_to_status_id,
                                'in_reply_to_status_id_str' => $in_reply_to_status_id_str,
-                               'source' => (($lastwall['app']) ? $lastwall['app'] : 'web'),
-                               'id' => intval($lastwall['id']),
-                               'id_str' => (string) $lastwall['id'],
                                'in_reply_to_user_id' => $in_reply_to_user_id,
                                'in_reply_to_user_id_str' => $in_reply_to_user_id_str,
                                'in_reply_to_screen_name' => $in_reply_to_screen_name,
+                               'user' => $user_info,
                                'geo' => NULL,
+                               'coordinates' => "",
+                               'place' => "",
+                               'contributors' => "",
+                               'is_quote_status' => false,
+                               'retweet_count' => 0,
+                               'favorite_count' => 0,
                                'favorited' => $lastwall['starred'] ? true : false,
-                               'user' => $user_info,
+                               'retweeted' => false,
+                               'possibly_sensitive' => false,
+                               'lang' => "",
                                'statusnet_html'                => $converted["html"],
                                'statusnet_conversation_id'     => $lastwall['parent'],
                        );
                                $status_info["entities"] = $converted["entities"];
 
                        if (($lastwall['item_network'] != "") AND ($status["source"] == 'web'))
-                               $status_info["source"] = network_to_name($lastwall['item_network']);
-                       elseif (($lastwall['item_network'] != "") AND (network_to_name($lastwall['item_network']) != $status_info["source"]))
-                               $status_info["source"] = trim($status_info["source"].' ('.network_to_name($lastwall['item_network']).')');
+                               $status_info["source"] = network_to_name($lastwall['item_network'], $user_info['url']);
+                       elseif (($lastwall['item_network'] != "") AND (network_to_name($lastwall['item_network'], $user_info['url']) != $status_info["source"]))
+                               $status_info["source"] = trim($status_info["source"].' ('.network_to_name($lastwall['item_network'], $user_info['url']).')');
 
                        // "uid" and "self" are only needed for some internal stuff, so remove it from here
                        unset($status_info["user"]["uid"]);
                        unset($status_info["user"]["self"]);
                }
 
+               logger('status_info: '.print_r($status_info, true), LOGGER_DEBUG);
+
                if ($type == "raw")
                        return($status_info);
 
                                        $in_reply_to_status_id = intval($lastwall['parent']);
                                        $in_reply_to_status_id_str = (string) intval($lastwall['parent']);
 
-                                       $r = q("SELECT * FROM unique_contacts WHERE `url` = '%s'", dbesc(normalise_link($reply[0]['item-author'])));
+                                       $r = q("SELECT * FROM `unique_contacts` WHERE `url` = '%s'", dbesc(normalise_link($reply[0]['item-author'])));
                                        if ($r) {
                                                if ($r[0]['nick'] == "")
                                                        $r[0]['nick'] = api_get_nick($r[0]["url"]);
                                }
                        }
 
-                       $converted = api_convert_item($item);
+                       $converted = api_convert_item($lastwall);
 
                        $user_info['status'] = array(
                                'text' => $converted["text"],
                                $user_info["status"]["entities"] = $converted["entities"];
 
                        if (($lastwall['item_network'] != "") AND ($user_info["status"]["source"] == 'web'))
-                               $user_info["status"]["source"] = network_to_name($lastwall['item_network']);
-                       if (($lastwall['item_network'] != "") AND (network_to_name($lastwall['item_network']) != $user_info["status"]["source"]))
-                               $user_info["status"]["source"] = trim($user_info["status"]["source"].' ('.network_to_name($lastwall['item_network']).')');
+                               $user_info["status"]["source"] = network_to_name($lastwall['item_network'], $user_info['url']);
+                       if (($lastwall['item_network'] != "") AND (network_to_name($lastwall['item_network'], $user_info['url']) != $user_info["status"]["source"]))
+                               $user_info["status"]["source"] = trim($user_info["status"]["source"].' ('.network_to_name($lastwall['item_network'], $user_info['url']).')');
 
                }
 
                $userlist = array();
 
                if (isset($_GET["q"])) {
-                       $r = q("SELECT id FROM unique_contacts WHERE name='%s'", dbesc($_GET["q"]));
+                       $r = q("SELECT id FROM `unique_contacts` WHERE `name`='%s'", dbesc($_GET["q"]));
                        if (!count($r))
-                               $r = q("SELECT id FROM unique_contacts WHERE nick='%s'", dbesc($_GET["q"]));
+                               $r = q("SELECT `id` FROM `unique_contacts` WHERE `nick`='%s'", dbesc($_GET["q"]));
 
                        if (count($r)) {
                                foreach ($r AS $user) {
         *
         * http://developer.twitter.com/doc/get/statuses/home_timeline
         *
-        * TODO: Optional parameters
-        * TODO: Add reply info
+        * @TODO Optional parameters
+        * @TODO Add reply info
         */
        function api_statuses_home_timeline(&$a, $type){
                if (api_user()===false) return false;
                if ($conversation_id > 0)
                        $sql_extra .= ' AND `item`.`parent` = '.intval($conversation_id);
 
-               $r = q("SELECT `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
+               $r = q("SELECT STRAIGHT_JOIN `item`.*, `item`.`id` AS `item_id`, `item`.`network` AS `item_network`,
                        `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
                        `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn-id`, `contact`.`self`,
                        `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`
 
                logger('API: api_conversation_show: '.$id);
 
+               $r = q("SELECT `parent` FROM `item` WHERE `id` = %d", intval($id));
+               if ($r)
+                       $id = $r[0]["parent"];
+
                $sql_extra = '';
 
                if ($max_id > 0)
                        if (!x($_REQUEST, "source"))
                                $_REQUEST["source"] = api_source();
 
-                       require_once('mod/item.php');
                        item_post($a);
                }
 
 
                $ret = api_statuses_show($a, $type);
 
-               require_once('include/items.php');
                drop_item($id, false);
 
                return($ret);
        function api_favorites_create_destroy(&$a, $type){
                if (api_user()===false) return false;
 
-               # for versioned api.
-               # TODO: we need a better global soluton
+               // for versioned api.
+               /// @TODO We need a better global soluton
                $action_argv_id=2;
                if ($a->argv[1]=="1.1") $action_argv_id=3;
 
        }
 
        function api_get_entitities(&$text, $bbcode) {
-               /*
-               To-Do:
-               * Links at the first character of the post
-               */
+               /// @todo
+               /// Links at the first character of the post
 
                $a = get_app();
 
                $include_entities = strtolower(x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:"false");
 
                if ($include_entities != "true") {
-                       require_once("mod/proxy.php");
 
                        preg_match_all("/\[img](.*?)\[\/img\]/ism", $bbcode, $images);
 
                                        // If image cache is activated, then use the following sizes:
                                        // thumb  (150), small (340), medium (600) and large (1024)
                                        if (!get_config("system", "proxy_disabled")) {
-                                               require_once("mod/proxy.php");
                                                $media_url = proxy_url($url);
 
                                                $sizes = array();
                                        intval(api_user()),
                                        intval($in_reply_to_status_id));
                                if ($r) {
-                                       $r = q("SELECT * FROM unique_contacts WHERE `url` = '%s'", dbesc(normalise_link($r[0]['author-link'])));
+                                       $r = q("SELECT * FROM `unique_contacts` WHERE `url` = '%s'", dbesc(normalise_link($r[0]['author-link'])));
 
                                        if ($r) {
                                                if ($r[0]['nick'] == "")
                                $status["entities"] = $converted["entities"];
 
                        if (($item['item_network'] != "") AND ($status["source"] == 'web'))
-                               $status["source"] = network_to_name($item['item_network']);
-                       else if (($item['item_network'] != "") AND (network_to_name($item['item_network']) != $status["source"]))
-                               $status["source"] = trim($status["source"].' ('.network_to_name($item['item_network']).')');
+                               $status["source"] = network_to_name($item['item_network'], $user_info['url']);
+                       else if (($item['item_network'] != "") AND (network_to_name($item['item_network'], $user_info['url']) != $status["source"]))
+                               $status["source"] = trim($status["source"].' ('.network_to_name($item['item_network'], $user_info['url']).')');
 
 
                        // Retweets are only valid for top postings
                        unset($status["user"]["uid"]);
                        unset($status["user"]["self"]);
 
-                       // 'geo' => array('type' => 'Point',
-                       //                   'coordinates' => array((float) $notice->lat,
-                       //                                          (float) $notice->lon));
+                       if ($item["coord"] != "") {
+                               $coords = explode(' ',$item["coord"]);
+                               if (count($coords) == 2) {
+                                       $status["geo"] = array('type' => 'Point',
+                                                       'coordinates' => array((float) $coords[0],
+                                                                               (float) $coords[1]));
+                               }
+                       }
 
                        $ret[] = $status;
                };
 
                $stringify_ids = (x($_REQUEST,'stringify_ids')?$_REQUEST['stringify_ids']:false);
 
-               $r = q("SELECT unique_contacts.id FROM contact, unique_contacts WHERE contact.nurl = unique_contacts.url AND `uid` = %d AND `self` = 0 AND `blocked` = 0 AND `pending` = 0 $sql_extra",
+               $r = q("SELECT `unique_contact`.`id` FROM contact, `unique_contacts` WHERE contact.nurl = unique_contacts.url AND `uid` = %d AND `self` = 0 AND `blocked` = 0 AND `pending` = 0 $sql_extra",
                        intval(api_user())
                );
 
 
                $sender = api_get_user($a);
 
-               require_once("include/message.php");
-
                if ($_POST['screen_name']) {
                        $r = q("SELECT `id`, `nurl`, `network` FROM `contact` WHERE `uid`=%d AND `nick`='%s'",
                                        intval(api_user()),
 
 
 
+       /**
+        * similar as /mod/redir.php
+        * redirect to 'url' after dfrn auth
+        *
+        * why this when there is mod/redir.php already?
+        * This use api_user() and api_login()
+        *
+        * params
+        *              c_url: url of remote contact to auth to
+        *              url: string, url to redirect after auth
+        */
+       function api_friendica_remoteauth(&$a) {
+               $url = ((x($_GET,'url')) ? $_GET['url'] : '');
+               $c_url = ((x($_GET,'c_url')) ? $_GET['c_url'] : '');
+
+               if ($url === '' || $c_url === '')
+                       die((api_error($a, 'json', "Wrong parameters")));
+
+               $c_url = normalise_link($c_url);
+
+               // traditional DFRN
+
+               $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `nurl` = '%s' LIMIT 1",
+                       dbesc($c_url),
+                       intval(api_user())
+               );
+
+               if ((! count($r)) || ($r[0]['network'] !== NETWORK_DFRN))
+                       die((api_error($a, 'json', "Unknown contact")));
+
+               $cid = $r[0]['id'];
+
+               $dfrn_id = $orig_id = (($r[0]['issued-id']) ? $r[0]['issued-id'] : $r[0]['dfrn-id']);
+
+               if($r[0]['duplex'] && $r[0]['issued-id']) {
+                       $orig_id = $r[0]['issued-id'];
+                       $dfrn_id = '1:' . $orig_id;
+               }
+               if($r[0]['duplex'] && $r[0]['dfrn-id']) {
+                       $orig_id = $r[0]['dfrn-id'];
+                       $dfrn_id = '0:' . $orig_id;
+               }
+
+               $sec = random_string();
+
+               q("INSERT INTO `profile_check` ( `uid`, `cid`, `dfrn_id`, `sec`, `expire`)
+                       VALUES( %d, %s, '%s', '%s', %d )",
+                       intval(api_user()),
+                       intval($cid),
+                       dbesc($dfrn_id),
+                       dbesc($sec),
+                       intval(time() + 45)
+               );
+
+               logger($r[0]['name'] . ' ' . $sec, LOGGER_DEBUG);
+               $dest = (($url) ? '&destination_url=' . $url : '');
+               goaway ($r[0]['poll'] . '?dfrn_id=' . $dfrn_id
+                               . '&dfrn_version=' . DFRN_PROTOCOL_VERSION
+                               . '&type=profile&sec=' . $sec . $dest . $quiet );
+       }
+       api_register_func('api/friendica/remoteauth', 'api_friendica_remoteauth', true);
+
+
+
 function api_share_as_retweet(&$item) {
        $body = trim($item["body"]);
 
@@ -2735,16 +2871,28 @@ function api_share_as_retweet(&$item) {
 }
 
 function api_get_nick($profile) {
-/* To-Do:
- - remove trailing jung from profile url
- - pump.io check has to check the website
-*/
+/// @TODO Remove trailing junk from profile url
+/// @TODO pump.io check has to check the website
 
        $nick = "";
 
-       $friendica = preg_replace("=https?://(.*)/profile/(.*)=ism", "$2", $profile);
-       if ($friendica != $profile)
-               $nick = $friendica;
+       $r = q("SELECT `nick` FROM `gcontact` WHERE `nurl` = '%s'",
+               dbesc(normalise_link($profile)));
+       if ($r)
+               $nick = $r[0]["nick"];
+
+       if (!$nick == "") {
+               $r = q("SELECT `nick` FROM `contact` WHERE `uid` = 0 AND `nurl` = '%s'",
+                       dbesc(normalise_link($profile)));
+               if ($r)
+                       $nick = $r[0]["nick"];
+       }
+
+       if (!$nick == "") {
+               $friendica = preg_replace("=https?://(.*)/profile/(.*)=ism", "$2", $profile);
+               if ($friendica != $profile)
+                       $nick = $friendica;
+       }
 
        if (!$nick == "") {
                $diaspora = preg_replace("=https?://(.*)/u/(.*)=ism", "$2", $profile);
@@ -2772,7 +2920,7 @@ function api_get_nick($profile) {
                }
        }
 
-       // To-Do: look at the page if its really a pumpio site
+       /// @TODO Look at the page if its really a pumpio site
        //if (!$nick == "") {
        //      $pumpio = preg_replace("=https?://(.*)/(.*)/=ism", "$2", $profile."/");
        //      if ($pumpio != $profile)
@@ -2782,8 +2930,8 @@ function api_get_nick($profile) {
        //}
 
        if ($nick != "") {
-               q("UPDATE unique_contacts SET nick = '%s' WHERE url = '%s'",
-                       dbesc($nick), dbesc(normalise_link($profile)));
+               q("UPDATE `unique_contacts` SET `nick` = '%s' WHERE `nick` != '%s' AND url = '%s'",
+                       dbesc($nick), dbesc($nick), dbesc(normalise_link($profile)));
                return($nick);
        }
 
@@ -2884,7 +3032,220 @@ function api_best_nickname(&$contacts) {
                $contacts = array($contacts[0]);
 }
 
+       // return all or a specified group of the user with the containing contacts
+       function api_friendica_group_show(&$a, $type) {
+               if (api_user()===false) return false;           
+
+               // params
+               $user_info = api_get_user($a);
+               $gid = (x($_REQUEST,'gid') ? $_REQUEST['gid'] : 0);
+               $uid = $user_info['uid'];
+       
+               // get data of the specified group id or all groups if not specified
+               if ($gid != 0) {
+                       $r = q("SELECT * FROM `group` WHERE `deleted` = 0 AND `uid` = %d AND `id` = %d",
+                               intval($uid), 
+                               intval($gid));
+                       // error message if specified gid is not in database
+                       if (count($r) == 0) 
+                               die(api_error($a, $type, 'gid not available'));
+               }
+               else 
+                       $r = q("SELECT * FROM `group` WHERE `deleted` = 0 AND `uid` = %d",
+                               intval($uid));
+               
+               // loop through all groups and retrieve all members for adding data in the user array
+               foreach ($r as $rr) {
+                       $members = group_get_members($rr['id']);
+                       $users = array();
+                       foreach ($members as $member) {
+                               $user = api_get_user($a, $member['nurl']);
+                               $users[] = $user;
+                       }
+                       $grps[] = array('name' => $rr['name'], 'gid' => $rr['id'], 'user' => $users);
+               }
+               return api_apply_template("group_show", $type, array('$groups' => $grps));
+       }
+       api_register_func('api/friendica/group_show', 'api_friendica_group_show', true);
+
+
+       // delete the specified group of the user
+       function api_friendica_group_delete(&$a, $type) {
+               if (api_user()===false) return false;           
+
+               // params
+               $user_info = api_get_user($a);
+               $gid = (x($_REQUEST,'gid') ? $_REQUEST['gid'] : 0);
+               $name = (x($_REQUEST, 'name') ? $_REQUEST['name'] : "");
+               $uid = $user_info['uid'];
+       
+               // error if no gid specified
+               if ($gid == 0 || $name == "")
+                       die(api_error($a, $type, 'gid or name not specified'));
+
+               // get data of the specified group id
+               $r = q("SELECT * FROM `group` WHERE `uid` = %d AND `id` = %d",
+                       intval($uid), 
+                       intval($gid));
+               // error message if specified gid is not in database
+               if (count($r) == 0) 
+                       die(api_error($a, $type, 'gid not available'));
+
+               // get data of the specified group id and group name
+               $rname = q("SELECT * FROM `group` WHERE `uid` = %d AND `id` = %d AND `name` = '%s'",
+                       intval($uid), 
+                       intval($gid),
+                       dbesc($name));
+               // error message if specified gid is not in database
+               if (count($rname) == 0) 
+                       die(api_error($a, $type, 'wrong group name'));
+
+               // delete group
+               $ret = group_rmv($uid, $name);
+               if ($ret) {
+                       // return success
+                       $success = array('success' => $ret, 'gid' => $gid, 'name' => $name, 'status' => 'deleted', 'wrong users' => array());
+                       return api_apply_template("group_delete", $type, array('$result' => $success));
+               }
+               else
+                       die(api_error($a, $type, 'other API error'));
+       }
+       api_register_func('api/friendica/group_delete', 'api_friendica_group_delete', true);
+
+
+       // create the specified group with the posted array of contacts 
+       function api_friendica_group_create(&$a, $type) {
+               if (api_user()===false) return false;           
+
+               // params
+               $user_info = api_get_user($a);
+               $name = (x($_REQUEST, 'name') ? $_REQUEST['name'] : "");
+               $uid = $user_info['uid'];
+               $json = json_decode($_POST['json'], true);
+               $users = $json['user'];
+
+               // error if no name specified
+               if ($name == "")
+                       die(api_error($a, $type, 'group name not specified'));
+
+               // get data of the specified group name
+               $rname = q("SELECT * FROM `group` WHERE `uid` = %d AND `name` = '%s' AND `deleted` = 0",
+                       intval($uid), 
+                       dbesc($name));
+               // error message if specified group name already exists
+               if (count($rname) != 0) 
+                       die(api_error($a, $type, 'group name already exists'));
+
+               // check if specified group name is a deleted group
+               $rname = q("SELECT * FROM `group` WHERE `uid` = %d AND `name` = '%s' AND `deleted` = 1",
+                       intval($uid), 
+                       dbesc($name));
+               // error message if specified group name already exists
+               if (count($rname) != 0) 
+                       $reactivate_group = true;
+
+               // create group
+               $ret = group_add($uid, $name);
+               if ($ret) 
+                       $gid = group_byname($uid, $name);
+               else
+                       die(api_error($a, $type, 'other API error'));
+               
+               // add members
+               $erroraddinguser = false;
+               $errorusers = array();
+               foreach ($users as $user) {
+                       $cid = $user['cid'];
+                       // check if user really exists as contact
+                       $contact = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d", 
+                               intval($cid),
+                               intval($uid));
+                       if (count($contact))
+                               $result = group_add_member($uid, $name, $cid, $gid);
+                       else {
+                               $erroraddinguser = true;
+                               $errorusers[] = $cid;
+                       }
+               }
+
+               // return success message incl. missing users in array
+               $status = ($erroraddinguser ? "missing user" : ($reactivate_group ? "reactivated" : "ok"));
+               $success = array('success' => true, 'gid' => $gid, 'name' => $name, 'status' => $status, 'wrong users' => $errorusers);
+               return api_apply_template("group_create", $type, array('result' => $success));          
+       }
+       api_register_func('api/friendica/group_create', 'api_friendica_group_create', true);
+
+
+       // update the specified group with the posted array of contacts 
+       function api_friendica_group_update(&$a, $type) {
+               if (api_user()===false) return false;           
+
+               // params
+               $user_info = api_get_user($a);
+               $uid = $user_info['uid'];
+               $gid = (x($_REQUEST, 'gid') ? $_REQUEST['gid'] : 0);
+               $name = (x($_REQUEST, 'name') ? $_REQUEST['name'] : "");
+               $json = json_decode($_POST['json'], true);
+               $users = $json['user'];
+
+               // error if no name specified
+               if ($name == "")
+                       die(api_error($a, $type, 'group name not specified'));
+
+               // error if no gid specified
+               if ($gid == "")
+                       die(api_error($a, $type, 'gid not specified'));
+
+               // remove members
+               $members = group_get_members($gid);
+               foreach ($members as $member) {
+                       $cid = $member['id'];
+                       foreach ($users as $user) {
+                               $found = ($user['cid'] == $cid ? true : false);
+                       }
+                       if (!$found) {
+                               $ret = group_rmv_member($uid, $name, $cid);
+                       }
+               }
+
+               // add members
+               $erroraddinguser = false;
+               $errorusers = array();
+               foreach ($users as $user) {
+                       $cid = $user['cid'];
+                       // check if user really exists as contact
+                       $contact = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d", 
+                               intval($cid),
+                               intval($uid));
+                       if (count($contact))
+                               $result = group_add_member($uid, $name, $cid, $gid);
+                       else {
+                               $erroraddinguser = true;
+                               $errorusers[] = $cid;
+                       }
+               }
+               
+               // return success message incl. missing users in array
+               $status = ($erroraddinguser ? "missing user" : "ok");
+               $success = array('success' => true, 'gid' => $gid, 'name' => $name, 'status' => $status, 'wrong users' => $errorusers);
+               return api_apply_template("group_update", $type, array('result' => $success));          
+       }
+       api_register_func('api/friendica/group_update', 'api_friendica_group_update', true);
+
 /*
+To.Do:
+    [pagename] => api/1.1/statuses/lookup.json
+    [id] => 605138389168451584
+    [include_cards] => true
+    [cards_platform] => Android-12
+    [include_entities] => true
+    [include_my_retweet] => 1
+    [include_rts] => 1
+    [include_reply_count] => true
+    [include_descendent_reply_count] => true
+
+
+
 Not implemented by now:
 statuses/retweets_of_me
 friendships/create