]> git.mxchange.org Git - friendica-addons.git/blob - appnet/appnet.php
App.net/Pump.io/GNU Social/Twitter: Support for new notifications
[friendica-addons.git] / appnet / appnet.php
1 <?php
2
3 /**
4  * Name: App.net Connector
5  * Description: Bidirectional (posting and reading) connector for app.net.
6  * Version: 0.2
7  * Author: Michael Vogel <https://pirati.ca/profile/heluecht>
8  */
9
10 /*
11  To-Do:
12  - Use embedded pictures for the attachment information (large attachment)
13  - Sound links must be handled
14  - https://alpha.app.net/sr_rolando/post/32365203 - double pictures
15  - https://alpha.app.net/opendev/post/34396399 - location data
16 */
17
18 require_once('include/enotify.php');
19
20 define('APPNET_DEFAULT_POLL_INTERVAL', 5); // given in minutes
21
22 function appnet_install() {
23         register_hook('post_local',             'addon/appnet/appnet.php', 'appnet_post_local');
24         register_hook('notifier_normal',        'addon/appnet/appnet.php', 'appnet_send');
25         register_hook('jot_networks',           'addon/appnet/appnet.php', 'appnet_jot_nets');
26         register_hook('cron',                   'addon/appnet/appnet.php', 'appnet_cron');
27         register_hook('connector_settings',     'addon/appnet/appnet.php', 'appnet_settings');
28         register_hook('connector_settings_post','addon/appnet/appnet.php', 'appnet_settings_post');
29         register_hook('prepare_body',           'addon/appnet/appnet.php', 'appnet_prepare_body');
30         register_hook('check_item_notification','addon/appnet/appnet.php', 'appnet_check_item_notification');
31 }
32
33
34 function appnet_uninstall() {
35         unregister_hook('post_local',       'addon/appnet/appnet.php', 'appnet_post_local');
36         unregister_hook('notifier_normal',  'addon/appnet/appnet.php', 'appnet_send');
37         unregister_hook('jot_networks',     'addon/appnet/appnet.php', 'appnet_jot_nets');
38         unregister_hook('cron',                 'addon/appnet/appnet.php', 'appnet_cron');
39         unregister_hook('connector_settings',   'addon/appnet/appnet.php', 'appnet_settings');
40         unregister_hook('connector_settings_post', 'addon/appnet/appnet.php', 'appnet_settings_post');
41         unregister_hook('prepare_body',         'addon/appnet/appnet.php', 'appnet_prepare_body');
42         unregister_hook('check_item_notification','addon/appnet/appnet.php', 'appnet_check_item_notification');
43 }
44
45 function appnet_module() {}
46
47 function appnet_content(&$a) {
48         if(! local_user()) {
49                 notice( t('Permission denied.') . EOL);
50                 return '';
51         }
52
53         require_once("mod/settings.php");
54         settings_init($a);
55
56         if (isset($a->argv[1]))
57                 switch ($a->argv[1]) {
58                         case "connect":
59                                 $o = appnet_connect($a);
60                                 break;
61                         default:
62                                 $o = print_r($a->argv, true);
63                                 break;
64                 }
65         else
66                 $o = appnet_connect($a);
67
68         return $o;
69 }
70
71 function appnet_check_item_notification($a, &$notification_data) {
72         $own_id = get_pconfig($notification_data["uid"], 'appnet', 'ownid');
73
74         $own_user = q("SELECT `url` FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
75                         intval($notification_data["uid"]),
76                         dbesc("adn::".$own_id)
77                 );
78
79         if ($own_user)
80                 $notification_data["profiles"][] = $own_user[0]["url"];
81 }
82
83 function appnet_plugin_admin(&$a, &$o){
84         $t = get_markup_template( "admin.tpl", "addon/appnet/" );
85
86         $o = replace_macros($t, array(
87                 '$submit' => t('Save Settings'),
88                                                                 // name, label, value, help, [extra values]
89                 '$clientid' => array('clientid', t('Client ID'),  get_config('appnet', 'clientid' ), ''),
90                 '$clientsecret' => array('clientsecret', t('Client Secret'),  get_config('appnet', 'clientsecret' ), ''),
91         ));
92 }
93
94 function appnet_plugin_admin_post(&$a){
95         $clientid     =       ((x($_POST,'clientid'))              ? notags(trim($_POST['clientid']))   : '');
96         $clientsecret =       ((x($_POST,'clientsecret'))   ? notags(trim($_POST['clientsecret'])): '');
97         set_config('appnet','clientid',$clientid);
98         set_config('appnet','clientsecret',$clientsecret);
99         info( t('Settings updated.'). EOL );
100 }
101
102 function appnet_connect(&$a) {
103         require_once 'addon/appnet/AppDotNet.php';
104
105         $clientId     = get_config('appnet','clientid');
106         $clientSecret = get_config('appnet','clientsecret');
107
108         if (($clientId == "") OR ($clientSecret == "")) {
109                 $clientId     = get_pconfig(local_user(),'appnet','clientid');
110                 $clientSecret = get_pconfig(local_user(),'appnet','clientsecret');
111         }
112
113         $app = new AppDotNet($clientId, $clientSecret);
114
115         try {
116                 $token = $app->getAccessToken($a->get_baseurl().'/appnet/connect');
117
118                 logger("appnet_connect: authenticated");
119                 $o .= t("You are now authenticated to app.net. ");
120                 set_pconfig(local_user(),'appnet','token', $token);
121         }
122         catch (AppDotNetException $e) {
123                 $o .= t("<p>Error fetching token. Please try again.</p>");
124         }
125
126         $o .= '<br /><a href="'.$a->get_baseurl().'/settings/connectors">'.t("return to the connector page").'</a>';
127
128         return($o);
129 }
130
131 function appnet_jot_nets(&$a,&$b) {
132         if(! local_user())
133                 return;
134
135         $post = get_pconfig(local_user(),'appnet','post');
136         if(intval($post) == 1) {
137                 $defpost = get_pconfig(local_user(),'appnet','post_by_default');
138                 $selected = ((intval($defpost) == 1) ? ' checked="checked" ' : '');
139                 $b .= '<div class="profile-jot-net"><input type="checkbox" name="appnet_enable"' . $selected . ' value="1" /> '
140                         . t('Post to app.net') . '</div>';
141     }
142 }
143
144 function appnet_settings(&$a,&$s) {
145         require_once 'addon/appnet/AppDotNet.php';
146
147         if(! local_user())
148                 return;
149
150         $token = get_pconfig(local_user(),'appnet','token');
151
152         $app_clientId     = get_config('appnet','clientid');
153         $app_clientSecret = get_config('appnet','clientsecret');
154
155         if (($app_clientId == "") OR ($app_clientSecret == "")) {
156                 $app_clientId     = get_pconfig(local_user(),'appnet','clientid');
157                 $app_clientSecret = get_pconfig(local_user(),'appnet','clientsecret');
158         }
159
160         /* Add our stylesheet to the page so we can make our settings look nice */
161         $a->page['htmlhead'] .= '<link rel="stylesheet"  type="text/css" href="' . $a->get_baseurl() . '/addon/appnet/appnet.css' . '" media="all" />' . "\r\n";
162
163         $enabled = get_pconfig(local_user(),'appnet','post');
164         $checked = (($enabled) ? ' checked="checked" ' : '');
165
166         $css = (($enabled) ? '' : '-disabled');
167
168         $def_enabled = get_pconfig(local_user(),'appnet','post_by_default');
169         $def_checked = (($def_enabled) ? ' checked="checked" ' : '');
170
171         $importenabled = get_pconfig(local_user(),'appnet','import');
172         $importchecked = (($importenabled) ? ' checked="checked" ' : '');
173
174         $ownid =  get_pconfig(local_user(),'appnet','ownid');
175
176         $s .= '<span id="settings_appnet_inflated" class="settings-block fakelink" style="display: block;" onclick="openClose(\'settings_appnet_expanded\'); openClose(\'settings_appnet_inflated\');">';
177         $s .= '<img class="connector'.$css.'" src="images/appnet.png" /><h3 class="connector">'. t('App.net Import/Export').'</h3>';
178         $s .= '</span>';
179         $s .= '<div id="settings_appnet_expanded" class="settings-block" style="display: none;">';
180         $s .= '<span class="fakelink" onclick="openClose(\'settings_appnet_expanded\'); openClose(\'settings_appnet_inflated\');">';
181         $s .= '<img class="connector'.$css.'" src="images/appnet.png" /><h3 class="connector">'. t('App.net Import/Export').'</h3>';
182         $s .= '</span>';
183
184         if ($token != "") {
185                 $app = new AppDotNet($app_clientId, $app_clientSecret);
186                 $app->setAccessToken($token);
187
188                 try {
189                         $userdata = $app->getUser();
190
191                         if ($ownid != $userdata["id"])
192                                 set_pconfig(local_user(),'appnet','ownid', $userdata["id"]);
193
194                         $s .= '<div id="appnet-info" ><img id="appnet-avatar" src="'.$userdata["avatar_image"]["url"].'" /><p id="appnet-info-block">'. t('Currently connected to: ') .'<a href="'.$userdata["canonical_url"].'" target="_appnet">'.$userdata["username"].'</a><br /><em>'.$userdata["description"]["text"].'</em></p></div>';
195                         $s .= '<div id="appnet-enable-wrapper">';
196                         $s .= '<label id="appnet-enable-label" for="appnet-checkbox">' . t('Enable App.net Post Plugin') . '</label>';
197                         $s .= '<input id="appnet-checkbox" type="checkbox" name="appnet" value="1" ' . $checked . '/>';
198                         $s .= '</div><div class="clear"></div>';
199
200                         $s .= '<div id="appnet-bydefault-wrapper">';
201                         $s .= '<label id="appnet-bydefault-label" for="appnet-bydefault">' . t('Post to App.net by default') . '</label>';
202                         $s .= '<input id="appnet-bydefault" type="checkbox" name="appnet_bydefault" value="1" ' . $def_checked . '/>';
203                         $s .= '</div><div class="clear"></div>';
204
205                         $s .= '<label id="appnet-import-label" for="appnet-import">'.t('Import the remote timeline').'</label>';
206                         $s .= '<input id="appnet-import" type="checkbox" name="appnet_import" value="1" '. $importchecked . '/>';
207                         $s .= '<div class="clear"></div>';
208
209                 }
210                 catch (AppDotNetException $e) {
211                         $s .= t("<p>Error fetching user profile. Please clear the configuration and try again.</p>");
212                 }
213
214         } elseif (($app_clientId == '') OR ($app_clientSecret == '')) {
215                 $s .= t("<p>You have two ways to connect to App.net.</p>");
216                 $s .= "<hr />";
217                 $s .= t('<p>First way: Register an application at <a href="https://account.app.net/developer/apps/">https://account.app.net/developer/apps/</a> and enter Client ID and Client Secret. ');
218                 $s .= sprintf(t("Use '%s' as Redirect URI<p>"), $a->get_baseurl().'/appnet/connect');
219                 $s .= '<div id="appnet-clientid-wrapper">';
220                 $s .= '<label id="appnet-clientid-label" for="appnet-clientid">' . t('Client ID') . '</label>';
221                 $s .= '<input id="appnet-clientid" type="text" name="clientid" value="" />';
222                 $s .= '</div><div class="clear"></div>';
223                 $s .= '<div id="appnet-clientsecret-wrapper">';
224                 $s .= '<label id="appnet-clientsecret-label" for="appnet-clientsecret">' . t('Client Secret') . '</label>';
225                 $s .= '<input id="appnet-clientsecret" type="text" name="clientsecret" value="" />';
226                 $s .= '</div><div class="clear"></div>';
227                 $s .= "<hr />";
228                 $s .= t('<p>Second way: fetch a token at <a href="http://dev-lite.jonathonduerig.com/">http://dev-lite.jonathonduerig.com/</a>. ');
229                 $s .= t("Set these scopes: 'Basic', 'Stream', 'Write Post', 'Public Messages', 'Messages'.</p>");
230                 $s .= '<div id="appnet-token-wrapper">';
231                 $s .= '<label id="appnet-token-label" for="appnet-token">' . t('Token') . '</label>';
232                 $s .= '<input id="appnet-token" type="text" name="token" value="'.$token.'" />';
233                 $s .= '</div><div class="clear"></div>';
234
235         } else {
236                 $app = new AppDotNet($app_clientId, $app_clientSecret);
237
238                 $scope =  array('basic', 'stream', 'write_post',
239                                 'public_messages', 'messages');
240
241                 $url = $app->getAuthUrl($a->get_baseurl().'/appnet/connect', $scope);
242                 $s .= '<div class="clear"></div>';
243                 $s .= '<a href="'.$url.'">'.t("Sign in using App.net").'</a>';
244         }
245
246         if (($app_clientId != '') OR ($app_clientSecret != '') OR ($token !='')) {
247                 $s .= '<div id="appnet-disconnect-wrapper">';
248                 $s .= '<label id="appnet-disconnect-label" for="appnet-disconnect">'. t('Clear OAuth configuration') .'</label>';
249
250                 $s .= '<input id="appnet-disconnect" type="checkbox" name="appnet-disconnect" value="1" />';
251                 $s .= '</div><div class="clear"></div>';
252         }
253
254         /* provide a submit button */
255         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="appnet-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
256
257         $s .= '</div>';
258 }
259
260 function appnet_settings_post(&$a,&$b) {
261
262         if(x($_POST,'appnet-submit')) {
263
264                 if (isset($_POST['appnet-disconnect'])) {
265                         del_pconfig(local_user(), 'appnet', 'clientsecret');
266                         del_pconfig(local_user(), 'appnet', 'clientid');
267                         del_pconfig(local_user(), 'appnet', 'token');
268                         del_pconfig(local_user(), 'appnet', 'post');
269                         del_pconfig(local_user(), 'appnet', 'post_by_default');
270                         del_pconfig(local_user(), 'appnet', 'import');
271                 }
272
273                 if (isset($_POST["clientsecret"]))
274                         set_pconfig(local_user(),'appnet','clientsecret', $_POST['clientsecret']);
275
276                 if (isset($_POST["clientid"]))
277                         set_pconfig(local_user(),'appnet','clientid', $_POST['clientid']);
278
279                 if (isset($_POST["token"]) AND ($_POST["token"] != ""))
280                         set_pconfig(local_user(),'appnet','token', $_POST['token']);
281
282                 set_pconfig(local_user(), 'appnet', 'post', intval($_POST['appnet']));
283                 set_pconfig(local_user(), 'appnet', 'post_by_default', intval($_POST['appnet_bydefault']));
284                 set_pconfig(local_user(), 'appnet', 'import', intval($_POST['appnet_import']));
285         }
286 }
287
288 function appnet_post_local(&$a,&$b) {
289         if($b['edit'])
290                 return;
291
292         if((local_user()) && (local_user() == $b['uid']) && (!$b['private']) && (!$b['parent'])) {
293                 $appnet_post = intval(get_pconfig(local_user(),'appnet','post'));
294                 $appnet_enable = (($appnet_post && x($_REQUEST,'appnet_enable')) ? intval($_REQUEST['appnet_enable']) : 0);
295
296                 // if API is used, default to the chosen settings
297                 if($_REQUEST['api_source'] && intval(get_pconfig(local_user(),'appnet','post_by_default')))
298                         $appnet_enable = 1;
299
300                 if(! $appnet_enable)
301                         return;
302
303                 if(strlen($b['postopts']))
304                         $b['postopts'] .= ',';
305
306                 $b['postopts'] .= 'appnet';
307         }
308 }
309
310 function appnet_create_entities($a, $b, $postdata) {
311         require_once("include/bbcode.php");
312         require_once("include/plaintext.php");
313
314         $bbcode = $b["body"];
315         $bbcode = bb_remove_share_information($bbcode, false, true);
316
317         // Change pure links in text to bbcode uris
318         $bbcode = preg_replace("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2]$2[/url]', $bbcode);
319
320         $URLSearchString = "^\[\]";
321
322         $bbcode = preg_replace("/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",'#$2',$bbcode);
323         $bbcode = preg_replace("/@\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",'@$2',$bbcode);
324         $bbcode = preg_replace("/\[bookmark\=([$URLSearchString]*)\](.*?)\[\/bookmark\]/ism",'[url=$1]$2[/url]',$bbcode);
325         $bbcode = preg_replace("/\[video\](.*?)\[\/video\]/ism",'[url=$1]$1[/url]',$bbcode);
326         $bbcode = preg_replace("/\[youtube\]https?:\/\/(.*?)\[\/youtube\]/ism",'[url=https://$1]https://$1[/url]',$bbcode);
327         $bbcode = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism",
328                                '[url=https://www.youtube.com/watch?v=$1]https://www.youtube.com/watch?v=$1[/url]', $bbcode);
329         $bbcode = preg_replace("/\[vimeo\]https?:\/\/(.*?)\[\/vimeo\]/ism",'[url=https://$1]https://$1[/url]',$bbcode);
330         $bbcode = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism",
331                                 '[url=https://vimeo.com/$1]https://vimeo.com/$1[/url]', $bbcode);
332         //$bbcode = preg_replace("/\[vimeo\](.*?)\[\/vimeo\]/ism",'[url=$1]$1[/url]',$bbcode);
333
334         $bbcode = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $bbcode);
335
336
337         preg_match_all("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", $bbcode, $urls, PREG_SET_ORDER);
338
339         $bbcode = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",'$1',$bbcode);
340
341         $b["body"] = $bbcode;
342
343         // To-Do:
344         // Bilder
345         // https://alpha.app.net/heluecht/post/32424376
346         // https://alpha.app.net/heluecht/post/32424307
347
348         $plaintext = plaintext($a, $b, 0, false, 6);
349
350         $text = $plaintext["text"];
351
352         $start = 0;
353         $entities = array();
354
355         foreach ($urls AS $url) {
356                 $lenurl = iconv_strlen($url[1], "UTF-8");
357                 $len = iconv_strlen($url[2], "UTF-8");
358                 $pos = iconv_strpos($text, $url[1], $start, "UTF-8");
359                 $pre = iconv_substr($text, 0, $pos, "UTF-8");
360                 $post = iconv_substr($text, $pos + $lenurl, 1000000, "UTF-8");
361
362                 $mid = $url[2];
363                 $html = bbcode($mid, false, false, 6);
364                 $mid = html2plain($html, 0, true);
365
366                 $mid = trim(html_entity_decode($mid,ENT_QUOTES,'UTF-8'));
367
368                 $text = $pre.$mid.$post;
369
370                 if ($mid != "")
371                         $entities[] = array("pos" => $pos, "len" => $len, "url" => $url[1], "text" => $mid);
372
373                 $start = $pos + 1;
374         }
375
376         if (isset($postdata["url"]) AND isset($postdata["title"]) AND ($postdata["type"] != "photo")) {
377                 $postdata["title"] = shortenmsg($postdata["title"], 90);
378                 $max = 256 - strlen($postdata["title"]);
379                 $text = shortenmsg($text, $max);
380                 $text .= "\n[".$postdata["title"]."](".$postdata["url"].")";
381         } elseif (isset($postdata["url"]) AND ($postdata["type"] != "photo")) {
382                 $postdata["url"] = short_link($postdata["url"]);
383                 $max = 240;
384                 $text = shortenmsg($text, $max);
385                 $text .= " [".$postdata["url"]."](".$postdata["url"].")";
386         } else {
387                 $max = 256;
388                 $text = shortenmsg($text, $max);
389         }
390
391         if (iconv_strlen($text, "UTF-8") < $max)
392                 $max = iconv_strlen($text, "UTF-8");
393
394         krsort($entities);
395         foreach ($entities AS $entity) {
396                 //if (iconv_strlen($text, "UTF-8") >= $entity["pos"] + $entity["len"]) {
397                 if (($entity["pos"] + $entity["len"]) <= $max) {
398                         $pre = iconv_substr($text, 0, $entity["pos"], "UTF-8");
399                         $post = iconv_substr($text, $entity["pos"] + $entity["len"], 1000000, "UTF-8");
400
401                         $text = $pre."[".$entity["text"]."](".$entity["url"].")".$post;
402                 }
403         }
404
405
406         return($text);
407 }
408
409 function appnet_send(&$a,&$b) {
410
411         logger('appnet_send: invoked for post '.$b['id']." ".$b['app']);
412
413         if (!get_pconfig($b["uid"],'appnet','import')) {
414                 if($b['deleted'] || $b['private'] || ($b['created'] !== $b['edited']))
415                         return;
416         }
417
418         if($b['parent'] != $b['id']) {
419                 logger("appnet_send: parameter ".print_r($b, true), LOGGER_DATA);
420
421                 // Looking if its a reply to an app.net post
422                 if ((substr($b["parent-uri"], 0, 5) != "adn::") AND (substr($b["extid"], 0, 5) != "adn::") AND (substr($b["thr-parent"], 0, 5) != "adn::")) {
423                         logger("appnet_send: no app.net post ".$b["parent"]);
424                         return;
425                 }
426
427                 $r = q("SELECT * FROM item WHERE item.uri = '%s' AND item.uid = %d LIMIT 1",
428                         dbesc($b["thr-parent"]),
429                         intval($b["uid"]));
430
431                 if(!count($r)) {
432                         logger("appnet_send: no parent found ".$b["thr-parent"]);
433                         return;
434                 } else {
435                         $iscomment = true;
436                         $orig_post = $r[0];
437                 }
438
439                 $nicknameplain = preg_replace("=https?://alpha.app.net/(.*)=ism", "$1", $orig_post["author-link"]);
440                 $nickname = "@[url=".$orig_post["author-link"]."]".$nicknameplain."[/url]";
441                 $nicknameplain = "@".$nicknameplain;
442
443                 logger("appnet_send: comparing ".$nickname." and ".$nicknameplain." with ".$b["body"], LOGGER_DEBUG);
444                 if ((strpos($b["body"], $nickname) === false) AND (strpos($b["body"], $nicknameplain) === false))
445                         $b["body"] = $nickname." ".$b["body"];
446
447                 logger("appnet_send: parent found ".print_r($orig_post, true), LOGGER_DATA);
448         } else {
449                 $iscomment = false;
450
451                 if($b['private'] OR !strstr($b['postopts'],'appnet'))
452                         return;
453         }
454
455         if (($b['verb'] == ACTIVITY_POST) AND $b['deleted'])
456                 appnet_action($a, $b["uid"], substr($orig_post["uri"], 5), "delete");
457
458         if($b['verb'] == ACTIVITY_LIKE) {
459                 logger("appnet_send: ".print_r($b, true), LOGGER_DEBUG);
460                 logger("appnet_send: parameter 2 ".substr($b["thr-parent"], 5), LOGGER_DEBUG);
461                 if ($b['deleted'])
462                         appnet_action($a, $b["uid"], substr($b["thr-parent"], 5), "unlike");
463                 else
464                         appnet_action($a, $b["uid"], substr($b["thr-parent"], 5), "like");
465                 return;
466         }
467
468         if($b['deleted'] || ($b['created'] !== $b['edited']))
469                 return;
470
471         $token = get_pconfig($b['uid'],'appnet','token');
472
473         if($token) {
474
475                 // If it's a repeated message from app.net then do a native repost and exit
476                 if (appnet_is_repost($a, $b['uid'], $b['body']))
477                         return;
478
479
480                 require_once 'addon/appnet/AppDotNet.php';
481
482                 $clientId     = get_pconfig($b["uid"],'appnet','clientid');
483                 $clientSecret = get_pconfig($b["uid"],'appnet','clientsecret');
484
485                 $app = new AppDotNet($clientId, $clientSecret);
486                 $app->setAccessToken($token);
487
488                 $data = array();
489
490                 require_once("include/plaintext.php");
491                 require_once("include/network.php");
492
493                 $post = plaintext($a, $b, 256, false, 6);
494                 logger("appnet_send: converted message ".$b["id"]." result: ".print_r($post, true), LOGGER_DEBUG);
495
496                 if (isset($post["image"])) {
497                         $img_str = fetch_url($post['image'],true, $redirects, 10);
498                         $tempfile = tempnam(get_temppath(), "cache");
499                         file_put_contents($tempfile, $img_str);
500
501                         try {
502                                 $photoFile = $app->createFile($tempfile, array(type => "com.github.jdolitsky.appdotnetphp.photo"));
503
504                                 $data["annotations"][] = array(
505                                                                 "type" => "net.app.core.oembed",
506                                                                 "value" => array(
507                                                                         "+net.app.core.file" => array(
508                                                                                 "file_id" => $photoFile["id"],
509                                                                                 "file_token" => $photoFile["file_token"],
510                                                                                 "format" => "oembed")
511                                                                         )
512                                                                 );
513                         }
514                         catch (AppDotNetException $e) {
515                                 logger("appnet_send: Error creating file ".appnet_error($e->getMessage()));
516                         }
517
518                         unlink($tempfile);
519                 }
520
521                 // Adding a link to the original post, if it is a root post
522                 if($b['parent'] == $b['id'])
523                         $data["annotations"][] = array(
524                                                         "type" => "net.app.core.crosspost",
525                                                         "value" => array("canonical_url" => $b["plink"])
526                                                         );
527
528                 // Adding the original post
529                 $attached_data = get_attached_data($b["body"]);
530                 $attached_data["post-uri"] = $b["uri"];
531                 $attached_data["post-title"] = $b["title"];
532                 $attached_data["post-body"] = substr($b["body"], 0, 4000); // To-Do: Better shortening
533                 $attached_data["post-tag"] = $b["tag"];
534                 $attached_data["author-name"] = $b["author-name"];
535                 $attached_data["author-link"] = $b["author-link"];
536                 $attached_data["author-avatar"] = $b["author-avatar"];
537
538                 $data["annotations"][] = array(
539                                                 "type" => "com.friendica.post",
540                                                 "value" => $attached_data
541                                                 );
542
543                 if (isset($post["url"]) AND !isset($post["title"]) AND ($post["type"] != "photo")) {
544                         $display_url = str_replace(array("http://www.", "https://www."), array("", ""), $post["url"]);
545                         $display_url = str_replace(array("http://", "https://"), array("", ""), $display_url);
546
547                         if (strlen($display_url) > 26)
548                                 $display_url = substr($display_url, 0, 25)."…";
549
550                         $post["title"] = $display_url;
551                 }
552
553                 $text = appnet_create_entities($a, $b, $post);
554
555                 $data["entities"]["parse_markdown_links"] = true;
556
557                 if ($iscomment)
558                         $data["reply_to"] = substr($orig_post["uri"], 5);
559
560                 try {
561                         logger("appnet_send: sending message ".$b["id"]." ".$text." ".print_r($data, true), LOGGER_DEBUG);
562                         $ret = $app->createPost($text, $data);
563                         logger("appnet_send: send message ".$b["id"]." result: ".print_r($ret, true), LOGGER_DEBUG);
564                         if ($iscomment) {
565                                 logger('appnet_send: Update extid '.$ret["id"]." for post id ".$b['id']);
566                                 q("UPDATE `item` SET `extid` = '%s' WHERE `id` = %d",
567                                         dbesc("adn::".$ret["id"]),
568                                         intval($b['id'])
569                                 );
570                         }
571                 }
572                 catch (AppDotNetException $e) {
573                         logger("appnet_send: Error sending message ".$b["id"]." ".appnet_error($e->getMessage()));
574                 }
575         }
576 }
577
578 function appnet_action($a, $uid, $pid, $action) {
579         require_once 'addon/appnet/AppDotNet.php';
580
581         $token        = get_pconfig($uid,'appnet','token');
582         $clientId     = get_pconfig($uid,'appnet','clientid');
583         $clientSecret = get_pconfig($uid,'appnet','clientsecret');
584
585         $app = new AppDotNet($clientId, $clientSecret);
586         $app->setAccessToken($token);
587
588         logger("appnet_action '".$action."' ID: ".$pid, LOGGER_DATA);
589
590         try {
591                 switch ($action) {
592                         case "delete":
593                                 $result = $app->deletePost($pid);
594                                 break;
595                         case "like":
596                                 $result = $app->starPost($pid);
597                                 break;
598                         case "unlike":
599                                 $result = $app->unstarPost($pid);
600                                 break;
601                 }
602                 logger("appnet_action '".$action."' send, result: " . print_r($result, true), LOGGER_DEBUG);
603         }
604         catch (AppDotNetException $e) {
605                 logger("appnet_action: Error sending action ".$action." pid ".$pid." ".appnet_error($e->getMessage()), LOGGER_DEBUG);
606         }
607 }
608
609 function appnet_is_repost($a, $uid, $body) {
610         $body = trim($body);
611
612         // Skip if it isn't a pure repeated messages
613         // Does it start with a share?
614         if (strpos($body, "[share") > 0)
615                 return(false);
616
617         // Does it end with a share?
618         if (strlen($body) > (strrpos($body, "[/share]") + 8))
619                 return(false);
620
621         $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body);
622         // Skip if there is no shared message in there
623         if ($body == $attributes)
624                 return(false);
625
626         $link = "";
627         preg_match("/link='(.*?)'/ism", $attributes, $matches);
628         if ($matches[1] != "")
629                 $link = $matches[1];
630
631         preg_match('/link="(.*?)"/ism', $attributes, $matches);
632         if ($matches[1] != "")
633                 $link = $matches[1];
634
635         $id = preg_replace("=https?://alpha.app.net/(.*)/post/(.*)=ism", "$2", $link);
636         if ($id == $link)
637                 return(false);
638
639         logger('appnet_is_repost: Reposting id '.$id.' for user '.$uid, LOGGER_DEBUG);
640
641         require_once 'addon/appnet/AppDotNet.php';
642
643         $token        = get_pconfig($uid,'appnet','token');
644         $clientId     = get_pconfig($uid,'appnet','clientid');
645         $clientSecret = get_pconfig($uid,'appnet','clientsecret');
646
647         $app = new AppDotNet($clientId, $clientSecret);
648         $app->setAccessToken($token);
649
650         try {
651                 $result = $app->repost($id);
652                 logger('appnet_is_repost: result '.print_r($result, true), LOGGER_DEBUG);
653                 return true;
654         }
655         catch (AppDotNetException $e) {
656                 logger('appnet_is_repost: error doing repost '.appnet_error($e->getMessage()), LOGGER_DEBUG);
657                 return false;
658         }
659 }
660
661 function appnet_fetchstream($a, $uid) {
662         require_once("addon/appnet/AppDotNet.php");
663         require_once('include/items.php');
664
665         $token = get_pconfig($uid,'appnet','token');
666         $clientId     = get_pconfig($uid,'appnet','clientid');
667         $clientSecret = get_pconfig($uid,'appnet','clientsecret');
668
669         $app = new AppDotNet($clientId, $clientSecret);
670         $app->setAccessToken($token);
671
672         $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
673                 intval($uid));
674
675         if(count($r))
676                 $me = $r[0];
677         else {
678                 logger("appnet_fetchstream: Own contact not found for user ".$uid, LOGGER_DEBUG);
679                 return;
680         }
681
682         $user = q("SELECT * FROM `user` WHERE `uid` = %d AND `account_expired` = 0 LIMIT 1",
683                 intval($uid)
684         );
685
686         if(count($user))
687                 $user = $user[0];
688         else {
689                 logger("appnet_fetchstream: Own user not found for user ".$uid, LOGGER_DEBUG);
690                 return;
691         }
692
693         $ownid = get_pconfig($uid,'appnet','ownid');
694
695         // Fetch stream
696         $param = array("count" => 200, "include_deleted" => false, "include_directed_posts" => true,
697                         "include_html" => false, "include_post_annotations" => true);
698
699         $lastid  = get_pconfig($uid, 'appnet', 'laststreamid');
700
701         if ($lastid <> "")
702                 $param["since_id"] = $lastid;
703
704         try {
705                 $stream = $app->getUserStream($param);
706         }
707         catch (AppDotNetException $e) {
708                 logger("appnet_fetchstream: Error fetching stream for user ".$uid." ".appnet_error($e->getMessage()));
709                 return;
710         }
711
712         if (!is_array($stream))
713                 $stream = array();
714
715         $stream = array_reverse($stream);
716         foreach ($stream AS $post) {
717                 $postarray = appnet_createpost($a, $uid, $post, $me, $user, $ownid, true);
718
719                 $item = item_store($postarray);
720                 $postarray["id"] = $item;
721
722                 logger('appnet_fetchstream: User '.$uid.' posted stream item '.$item);
723
724                 $lastid = $post["id"];
725
726                 if (($item != 0) AND ($postarray['contact-id'] != $me["id"]) AND !function_exists("check_item_notification")) {
727                         $r = q("SELECT `thread`.`iid` AS `parent` FROM `thread`
728                                 INNER JOIN `item` ON `thread`.`iid` = `item`.`parent` AND `thread`.`uid` = `item`.`uid`
729                                 WHERE `item`.`id` = %d AND `thread`.`mention` LIMIT 1", dbesc($item));
730
731                         if (count($r)) {
732                                 require_once('include/enotify.php');
733                                 notification(array(
734                                         'type'         => NOTIFY_COMMENT,
735                                         'notify_flags' => $user['notify-flags'],
736                                         'language'     => $user['language'],
737                                         'to_name'      => $user['username'],
738                                         'to_email'     => $user['email'],
739                                         'uid'          => $user['uid'],
740                                         'item'         => $postarray,
741                                         'link'         => $a->get_baseurl().'/display/'.urlencode(get_item_guid($item)),
742                                         'source_name'  => $postarray['author-name'],
743                                         'source_link'  => $postarray['author-link'],
744                                         'source_photo' => $postarray['author-avatar'],
745                                         'verb'         => ACTIVITY_POST,
746                                         'otype'        => 'item',
747                                         'parent'       => $r[0]["parent"],
748                                 ));
749                         }
750                 }
751         }
752
753         set_pconfig($uid, 'appnet', 'laststreamid', $lastid);
754
755         // Fetch mentions
756         $param = array("count" => 200, "include_deleted" => false, "include_directed_posts" => true,
757                         "include_html" => false, "include_post_annotations" => true);
758
759         $lastid  = get_pconfig($uid, 'appnet', 'lastmentionid');
760
761         if ($lastid <> "")
762                 $param["since_id"] = $lastid;
763
764         try {
765                 $mentions = $app->getUserMentions("me", $param);
766         }
767         catch (AppDotNetException $e) {
768                 logger("appnet_fetchstream: Error fetching mentions for user ".$uid." ".appnet_error($e->getMessage()));
769                 return;
770         }
771
772         if (!is_array($mentions))
773                 $mentions = array();
774
775         $mentions = array_reverse($mentions);
776         foreach ($mentions AS $post) {
777                 $postarray = appnet_createpost($a, $uid, $post, $me, $user, $ownid, false);
778
779                 if (isset($postarray["id"])) {
780                         $item = $postarray["id"];
781                         $parent_id = $postarray['parent'];
782                 } elseif (isset($postarray["body"])) {
783                         $item = item_store($postarray);
784                         $postarray["id"] = $item;
785
786                         $parent_id = 0;
787                         logger('appnet_fetchstream: User '.$uid.' posted mention item '.$item);
788
789                         if ($item AND function_exists("check_item_notification"))
790                                 check_item_notification($item, $uid, NOTIFY_TAGSELF);
791
792                 } else {
793                         $item = 0;
794                         $parent_id = 0;
795                 }
796
797                 // Fetch the parent and id
798                 if (($parent_id == 0) AND ($postarray['uri'] != "")) {
799                         $r = q("SELECT `id`, `parent` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
800                                 dbesc($postarray['uri']),
801                                 intval($uid)
802                         );
803
804                         if (count($r)) {
805                                 $item = $r[0]['id'];
806                                 $parent_id = $r[0]['parent'];
807                         }
808                 }
809
810                 $lastid = $post["id"];
811
812                 //if (($item != 0) AND ($postarray['contact-id'] != $me["id"])) {
813                 if (($item != 0) AND !function_exists("check_item_notification")) {
814                         require_once('include/enotify.php');
815                         notification(array(
816                                 'type'         => NOTIFY_TAGSELF,
817                                 'notify_flags' => $user['notify-flags'],
818                                 'language'     => $user['language'],
819                                 'to_name'      => $user['username'],
820                                 'to_email'     => $user['email'],
821                                 'uid'          => $user['uid'],
822                                 'item'         => $postarray,
823                                 'link'         => $a->get_baseurl().'/display/'.urlencode(get_item_guid($item)),
824                                 'source_name'  => $postarray['author-name'],
825                                 'source_link'  => $postarray['author-link'],
826                                 'source_photo' => $postarray['author-avatar'],
827                                 'verb'         => ACTIVITY_TAG,
828                                 'otype'        => 'item',
829                                 'parent'       => $parent_id,
830                         ));
831                 }
832         }
833
834         set_pconfig($uid, 'appnet', 'lastmentionid', $lastid);
835
836
837 /* To-Do
838         $param = array("interaction_actions" => "star");
839         $interactions = $app->getMyInteractions($param);
840         foreach ($interactions AS $interaction)
841                 appnet_dolike($a, $uid, $interaction);
842 */
843 }
844
845 function appnet_createpost($a, $uid, $post, $me, $user, $ownid, $createuser, $threadcompletion = true, $nodupcheck = false) {
846         require_once('include/items.php');
847
848         if ($post["machine_only"])
849                 return;
850
851         if ($post["is_deleted"])
852                 return;
853
854         $postarray = array();
855         $postarray['gravity'] = 0;
856         $postarray['uid'] = $uid;
857         $postarray['wall'] = 0;
858         $postarray['verb'] = ACTIVITY_POST;
859         $postarray['network'] =  dbesc(NETWORK_APPNET);
860         if (is_array($post["repost_of"])) {
861                 // You can't reply to reposts. So use the original id and thread-id
862                 $postarray['uri'] = "adn::".$post["repost_of"]["id"];
863                 $postarray['parent-uri'] = "adn::".$post["repost_of"]["thread_id"];
864         } else {
865                 $postarray['uri'] = "adn::".$post["id"];
866                 $postarray['parent-uri'] = "adn::".$post["thread_id"];
867         }
868
869         if (!$nodupcheck) {
870                 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
871                         dbesc($postarray['uri']),
872                         intval($uid)
873                         );
874
875                 if (count($r))
876                         return($r[0]);
877
878                 $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
879                         dbesc($postarray['uri']),
880                         intval($uid)
881                         );
882
883                 if (count($r))
884                         return($r[0]);
885         }
886
887         if (isset($post["reply_to"]) AND ($post["reply_to"] != "")) {
888                 $postarray['thr-parent'] = "adn::".$post["reply_to"];
889
890                 // Complete the thread (if the parent doesn't exists)
891                 if ($threadcompletion) {
892                         //$r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
893                         //      dbesc($postarray['thr-parent']),
894                         //      intval($uid)
895                         //      );
896                         //if (!count($r)) {
897                                 logger("appnet_createpost: completing thread ".$post["thread_id"]." for user ".$uid, LOGGER_DEBUG);
898
899                                 require_once("addon/appnet/AppDotNet.php");
900
901                                 $token = get_pconfig($uid,'appnet','token');
902                                 $clientId     = get_pconfig($uid,'appnet','clientid');
903                                 $clientSecret = get_pconfig($uid,'appnet','clientsecret');
904
905                                 $app = new AppDotNet($clientId, $clientSecret);
906                                 $app->setAccessToken($token);
907
908                                 $param = array("count" => 200, "include_deleted" => false, "include_directed_posts" => true,
909                                                 "include_html" => false, "include_post_annotations" => true);
910                                 try {
911                                         $thread = $app->getPostReplies($post["thread_id"], $param);
912                                 }
913                                 catch (AppDotNetException $e) {
914                                         logger("appnet_createpost: Error fetching thread for user ".$uid." ".appnet_error($e->getMessage()));
915                                 }
916                                 $thread = array_reverse($thread);
917
918                                 logger("appnet_createpost: fetched ".count($thread)." items for thread ".$post["thread_id"]." for user ".$uid, LOGGER_DEBUG);
919
920                                 foreach ($thread AS $tpost) {
921                                         $threadpost = appnet_createpost($a, $uid, $tpost, $me, $user, $ownid, false, false);
922                                         $item = item_store($threadpost);
923                                         $threadpost["id"] = $item;
924
925                                         logger("appnet_createpost: stored post ".$post["id"]." thread ".$post["thread_id"]." in item ".$item, LOGGER_DEBUG);
926                                 }
927                         //}
928                 }
929                 // Don't create accounts of people who just comment something
930                 $createuser = false;
931
932                 $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
933         } else {
934                 $postarray['thr-parent'] = $postarray['uri'];
935                 $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
936         }
937
938         if (($post["user"]["id"] != $ownid) OR ($postarray['thr-parent'] == $postarray['uri'])) {
939                 $postarray['owner-name'] = $post["user"]["name"];
940                 $postarray['owner-link'] = $post["user"]["canonical_url"];
941                 $postarray['owner-avatar'] = $post["user"]["avatar_image"]["url"];
942                 $postarray['contact-id'] = appnet_fetchcontact($a, $uid, $post["user"], $me, $createuser);
943         } else {
944                 $postarray['owner-name'] = $me["name"];
945                 $postarray['owner-link'] = $me["url"];
946                 $postarray['owner-avatar'] = $me["thumb"];
947                 $postarray['contact-id'] = $me["id"];
948         }
949
950         $links = array();
951
952         if (is_array($post["repost_of"])) {
953                 $postarray['author-name'] = $post["repost_of"]["user"]["name"];
954                 $postarray['author-link'] = $post["repost_of"]["user"]["canonical_url"];
955                 $postarray['author-avatar'] = $post["repost_of"]["user"]["avatar_image"]["url"];
956
957                 $content = $post["repost_of"];
958         } else {
959                 $postarray['author-name'] = $postarray['owner-name'];
960                 $postarray['author-link'] = $postarray['owner-link'];
961                 $postarray['author-avatar'] = $postarray['owner-avatar'];
962
963                 $content = $post;
964         }
965
966         $postarray['plink'] = $content["canonical_url"];
967
968         if (is_array($content["entities"])) {
969                 $converted = appnet_expand_entities($a, $content["text"], $content["entities"]);
970                 $postarray['body'] = $converted["body"];
971                 $postarray['tag'] = $converted["tags"];
972         } else
973                 $postarray['body'] = $content["text"];
974
975         if (sizeof($content["entities"]["links"]))
976                 foreach($content["entities"]["links"] AS $link) {
977                         $url = normalise_link($link["url"]);
978                         $links[$url] = $link["url"];
979                 }
980
981         /* if (sizeof($content["annotations"]))
982                 foreach($content["annotations"] AS $annotation) {
983                         if ($annotation[type] == "net.app.core.oembed") {
984                                 if (isset($annotation["value"]["embeddable_url"])) {
985                                         $url = normalise_link($annotation["value"]["embeddable_url"]);
986                                         if (isset($links[$url]))
987                                                 unset($links[$url]);
988                                 }
989                         } elseif ($annotation[type] == "com.friendica.post") {
990                                 //$links = array();
991                                 //if (isset($annotation["value"]["post-title"]))
992                                 //      $postarray['title'] = $annotation["value"]["post-title"];
993
994                                 //if (isset($annotation["value"]["post-body"]))
995                                 //      $postarray['body'] = $annotation["value"]["post-body"];
996
997                                 //if (isset($annotation["value"]["post-tag"]))
998                                 //      $postarray['tag'] = $annotation["value"]["post-tag"];
999
1000                                 if (isset($annotation["value"]["author-name"]))
1001                                         $postarray['author-name'] = $annotation["value"]["author-name"];
1002
1003                                 if (isset($annotation["value"]["author-link"]))
1004                                         $postarray['author-link'] = $annotation["value"]["author-link"];
1005
1006                                 if (isset($annotation["value"]["author-avatar"]))
1007                                         $postarray['author-avatar'] = $annotation["value"]["author-avatar"];
1008                         }
1009
1010                 } */
1011
1012         $page_info = "";
1013
1014         if (is_array($content["annotations"])) {
1015                 $photo = appnet_expand_annotations($a, $content["annotations"]);
1016                 if (($photo["large"] != "") AND ($photo["url"] != ""))
1017                         $page_info = "\n[url=".$photo["url"]."][img]".$photo["large"]."[/img][/url]";
1018                 elseif ($photo["url"] != "")
1019                         $page_info = "\n[img]".$photo["url"]."[/img]";
1020
1021                 if ($photo["url"] != "")
1022                         $postarray['object-type'] = ACTIVITY_OBJ_IMAGE;
1023
1024         } else
1025                 $photo = array("url" => "", "large" => "");
1026
1027         if (sizeof($links)) {
1028                 $link = array_pop($links);
1029                 $url = str_replace(array('/', '.'), array('\/', '\.'), $link);
1030
1031                 $page_info = add_page_info($link, false, $photo["url"]);
1032
1033                 if (trim($page_info) != "") {
1034                         $removedlink = preg_replace("/\[url\=".$url."\](.*?)\[\/url\]/ism", '', $postarray['body']);
1035                         if (($removedlink == "") OR strstr($postarray['body'], $removedlink))
1036                                 $postarray['body'] = $removedlink;
1037                 }
1038         }
1039
1040         $postarray['body'] .= $page_info;
1041
1042         $postarray['created'] = datetime_convert('UTC','UTC',$post["created_at"]);
1043         $postarray['edited'] = datetime_convert('UTC','UTC',$post["created_at"]);
1044
1045         $postarray['app'] = $post["source"]["name"];
1046
1047         return($postarray);
1048 }
1049
1050 function appnet_expand_entities($a, $body, $entities) {
1051
1052         if (!function_exists('substr_unicode')) {
1053                 function substr_unicode($str, $s, $l = null) {
1054                         return join("", array_slice(
1055                                 preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY), $s, $l));
1056                 }
1057         }
1058
1059         $tags_arr = array();
1060         $replace = array();
1061
1062         foreach ($entities["mentions"] AS $mention) {
1063                 $url = "@[url=https://alpha.app.net/".rawurlencode($mention["name"])."]".$mention["name"]."[/url]";
1064                 $tags_arr["@".$mention["name"]] = $url;
1065                 $replace[$mention["pos"]] = array("pos"=> $mention["pos"], "len"=> $mention["len"], "replace"=> $url);
1066         }
1067
1068         foreach ($entities["hashtags"] AS $hashtag) {
1069                 $url = "#[url=".$a->get_baseurl()."/search?tag=".rawurlencode($hashtag["name"])."]".$hashtag["name"]."[/url]";
1070                 $tags_arr["#".$hashtag["name"]] = $url;
1071                 $replace[$hashtag["pos"]] = array("pos"=> $hashtag["pos"], "len"=> $hashtag["len"], "replace"=> $url);
1072         }
1073
1074         foreach ($entities["links"] AS $links) {
1075                 $url = "[url=".$links["url"]."]".$links["text"]."[/url]";
1076                 if (isset($links["amended_len"]) AND ($links["amended_len"] > $links["len"]))
1077                         $replace[$links["pos"]] = array("pos"=> $links["pos"], "len"=> $links["amended_len"], "replace"=> $url);
1078                 else
1079                         $replace[$links["pos"]] = array("pos"=> $links["pos"], "len"=> $links["len"], "replace"=> $url);
1080         }
1081
1082
1083         if (sizeof($replace)) {
1084                 krsort($replace);
1085                 foreach ($replace AS $entity) {
1086                         $pre = substr_unicode($body, 0, $entity["pos"]);
1087                         $post = substr_unicode($body, $entity["pos"] + $entity["len"]);
1088                         //$pre = iconv_substr($body, 0, $entity["pos"], "UTF-8");
1089                         //$post = iconv_substr($body, $entity["pos"] + $entity["len"], "UTF-8");
1090
1091                         $body = $pre.$entity["replace"].$post;
1092                 }
1093         }
1094
1095         return(array("body" => $body, "tags" => implode($tags_arr, ",")));
1096 }
1097
1098 function appnet_expand_annotations($a, $annotations) {
1099         $photo = array("url" => "", "large" => "");
1100         foreach ($annotations AS $annotation) {
1101                 if (($annotation[type] == "net.app.core.oembed") AND
1102                         ($annotation["value"]["type"] == "photo")) {
1103                         if ($annotation["value"]["url"] != "")
1104                                 $photo["url"] = $annotation["value"]["url"];
1105
1106                         if ($annotation["value"]["thumbnail_large_url"] != "")
1107                                 $photo["large"] = $annotation["value"]["thumbnail_large_url"];
1108
1109                         //if (($annotation["value"]["thumbnail_large_url"] != "") AND ($annotation["value"]["url"] != ""))
1110                         //      $embedded = "\n[url=".$annotation["value"]["url"]."][img]".$annotation["value"]["thumbnail_large_url"]."[/img][/url]";
1111                         //elseif ($annotation["value"]["url"] != "")
1112                         //      $embedded = "\n[img]".$annotation["value"]["url"]."[/img]";
1113                 }
1114         }
1115         return $photo;
1116 }
1117
1118 function appnet_fetchcontact($a, $uid, $contact, $me, $create_user) {
1119
1120         if (function_exists("update_gcontact"))
1121                 update_gcontact(array("url" => $contact["canonical_url"], "generation" => 2,
1122                                 "network" => NETWORK_APPNET, "photo" => $contact["avatar_image"]["url"],
1123                                 "name" => $contact["name"], "nick" => $contact["username"],
1124                                 "about" => $contact["description"]["text"], "hide" => true,
1125                                 "addr" => $contact["username"]."@app.net"));
1126         else {
1127                 // Old Code
1128                 $r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
1129                                 dbesc(normalise_link($contact["canonical_url"])));
1130
1131                 if (count($r) == 0)
1132                         q("INSERT INTO unique_contacts (url, name, nick, avatar) VALUES ('%s', '%s', '%s', '%s')",
1133                                 dbesc(normalise_link($contact["canonical_url"])),
1134                                 dbesc($contact["name"]),
1135                                 dbesc($contact["username"]),
1136                                 dbesc($contact["avatar_image"]["url"]));
1137                 else
1138                         q("UPDATE unique_contacts SET name = '%s', nick = '%s', avatar = '%s' WHERE url = '%s'",
1139                                 dbesc($contact["name"]),
1140                                 dbesc($contact["username"]),
1141                                 dbesc($contact["avatar_image"]["url"]),
1142                                 dbesc(normalise_link($contact["canonical_url"])));
1143
1144                 if (DB_UPDATE_VERSION >= "1177")
1145                         q("UPDATE `unique_contacts` SET `location` = '%s', `about` = '%s' WHERE url = '%s'",
1146                                 dbesc(""),
1147                                 dbesc($contact["description"]["text"]),
1148                                 dbesc(normalise_link($contact["canonical_url"])));
1149         }
1150
1151         $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1152                 intval($uid), dbesc("adn::".$contact["id"]));
1153
1154         if(!count($r) AND !$create_user)
1155                 return($me["id"]);
1156
1157         if ($contact["canonical_url"] == "")
1158                 return($me["id"]);
1159
1160         if (count($r) AND ($r[0]["readonly"] OR $r[0]["blocked"])) {
1161                 logger("appnet_fetchcontact: Contact '".$r[0]["nick"]."' is blocked or readonly.", LOGGER_DEBUG);
1162                 return(-1);
1163         }
1164
1165         if(!count($r)) {
1166
1167                 if ($contact["name"] == "")
1168                         $contact["name"] = $contact["username"];
1169
1170                 if ($contact["username"] == "")
1171                         $contact["username"] = $contact["name"];
1172
1173                 // create contact record
1174                 q("INSERT INTO `contact` (`uid`, `created`, `url`, `nurl`, `addr`, `alias`, `notify`, `poll`,
1175                                         `name`, `nick`, `photo`, `network`, `rel`, `priority`,
1176                                         `writable`, `blocked`, `readonly`, `pending` )
1177                                         VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0 ) ",
1178                         intval($uid),
1179                         dbesc(datetime_convert()),
1180                         dbesc($contact["canonical_url"]),
1181                         dbesc(normalise_link($contact["canonical_url"])),
1182                         dbesc($contact["username"]."@app.net"),
1183                         dbesc("adn::".$contact["id"]),
1184                         dbesc(''),
1185                         dbesc("adn::".$contact["id"]),
1186                         dbesc($contact["name"]),
1187                         dbesc($contact["username"]),
1188                         dbesc($contact["avatar_image"]["url"]),
1189                         dbesc(NETWORK_APPNET),
1190                         intval(CONTACT_IS_FRIEND),
1191                         intval(1),
1192                         intval(1)
1193                 );
1194
1195                 $r = q("SELECT * FROM `contact` WHERE `alias` = '%s' AND `uid` = %d LIMIT 1",
1196                         dbesc("adn::".$contact["id"]),
1197                         intval($uid)
1198                         );
1199
1200                 if(! count($r))
1201                         return(false);
1202
1203                 $contact_id  = $r[0]['id'];
1204
1205                 $g = q("SELECT def_gid FROM user WHERE uid = %d LIMIT 1",
1206                         intval($uid)
1207                 );
1208
1209                 if($g && intval($g[0]['def_gid'])) {
1210                         require_once('include/group.php');
1211                         group_add_member($uid,'',$contact_id,$g[0]['def_gid']);
1212                 }
1213
1214                 require_once("Photo.php");
1215
1216                 $photos = import_profile_photo($contact["avatar_image"]["url"],$uid,$contact_id);
1217
1218                 q("UPDATE `contact` SET `photo` = '%s',
1219                                         `thumb` = '%s',
1220                                         `micro` = '%s',
1221                                         `name-date` = '%s',
1222                                         `uri-date` = '%s',
1223                                         `avatar-date` = '%s'
1224                                 WHERE `id` = %d",
1225                         dbesc($photos[0]),
1226                         dbesc($photos[1]),
1227                         dbesc($photos[2]),
1228                         dbesc(datetime_convert()),
1229                         dbesc(datetime_convert()),
1230                         dbesc(datetime_convert()),
1231                         intval($contact_id)
1232                 );
1233
1234                 if (DB_UPDATE_VERSION >= "1177")
1235                         q("UPDATE `contact` SET `location` = '%s',
1236                                                 `about` = '%s'
1237                                         WHERE `id` = %d",
1238                                 dbesc(""),
1239                                 dbesc($contact["description"]["text"]),
1240                                 intval($contact_id)
1241                         );
1242         } else {
1243                 // update profile photos once every two weeks as we have no notification of when they change.
1244
1245                 //$update_photo = (($r[0]['avatar-date'] < datetime_convert('','','now -2 days')) ? true : false);
1246                 $update_photo = ($r[0]['avatar-date'] < datetime_convert('','','now -12 hours'));
1247
1248                 // check that we have all the photos, this has been known to fail on occasion
1249
1250                 if((! $r[0]['photo']) || (! $r[0]['thumb']) || (! $r[0]['micro']) || ($update_photo)) {
1251
1252                         logger("appnet_fetchcontact: Updating contact ".$contact["username"], LOGGER_DEBUG);
1253
1254                         require_once("Photo.php");
1255
1256                         $photos = import_profile_photo($contact["avatar_image"]["url"], $uid, $r[0]['id']);
1257
1258                         q("UPDATE `contact` SET `photo` = '%s',
1259                                                 `thumb` = '%s',
1260                                                 `micro` = '%s',
1261                                                 `name-date` = '%s',
1262                                                 `uri-date` = '%s',
1263                                                 `avatar-date` = '%s',
1264                                                 `url` = '%s',
1265                                                 `nurl` = '%s',
1266                                                 `addr` = '%s',
1267                                                 `name` = '%s',
1268                                                 `nick` = '%s'
1269                                         WHERE `id` = %d",
1270                                 dbesc($photos[0]),
1271                                 dbesc($photos[1]),
1272                                 dbesc($photos[2]),
1273                                 dbesc(datetime_convert()),
1274                                 dbesc(datetime_convert()),
1275                                 dbesc(datetime_convert()),
1276                                 dbesc($contact["canonical_url"]),
1277                                 dbesc(normalise_link($contact["canonical_url"])),
1278                                 dbesc($contact["username"]."@app.net"),
1279                                 dbesc($contact["name"]),
1280                                 dbesc($contact["username"]),
1281                                 intval($r[0]['id'])
1282                         );
1283                         if (DB_UPDATE_VERSION >= "1177")
1284                                 q("UPDATE `contact` SET `location` = '%s',
1285                                                         `about` = '%s'
1286                                                 WHERE `id` = %d",
1287                                         dbesc(""),
1288                                         dbesc($contact["description"]["text"]),
1289                                         intval($r[0]['id'])
1290                                 );
1291                 }
1292         }
1293
1294         return($r[0]["id"]);
1295 }
1296
1297 function appnet_prepare_body(&$a,&$b) {
1298         if ($b["item"]["network"] != NETWORK_APPNET)
1299                 return;
1300
1301         if ($b["preview"]) {
1302                 $max_char = 256;
1303                 require_once("include/plaintext.php");
1304                 $item = $b["item"];
1305                 $item["plink"] = $a->get_baseurl()."/display/".$a->user["nickname"]."/".$item["parent"];
1306
1307                 $r = q("SELECT `author-link` FROM item WHERE item.uri = '%s' AND item.uid = %d LIMIT 1",
1308                         dbesc($item["thr-parent"]),
1309                         intval(local_user()));
1310
1311                 if(count($r)) {
1312                         $orig_post = $r[0];
1313
1314                         $nicknameplain = preg_replace("=https?://alpha.app.net/(.*)=ism", "$1", $orig_post["author-link"]);
1315                         $nickname = "@[url=".$orig_post["author-link"]."]".$nicknameplain."[/url]";
1316                         $nicknameplain = "@".$nicknameplain;
1317
1318                         if ((strpos($item["body"], $nickname) === false) AND (strpos($item["body"], $nicknameplain) === false))
1319                                 $item["body"] = $nickname." ".$item["body"];
1320                 }
1321
1322
1323
1324                 $msgarr = plaintext($a, $item, $max_char, true);
1325                 $msg = appnet_create_entities($a, $item, $msgarr);
1326
1327                 require_once("library/markdown.php");
1328                 $msg = Markdown($msg);
1329
1330                 $b['html'] = $msg;
1331         }
1332 }
1333
1334 function appnet_cron($a,$b) {
1335         $last = get_config('appnet','last_poll');
1336
1337         $poll_interval = intval(get_config('appnet','poll_interval'));
1338         if(! $poll_interval)
1339                 $poll_interval = APPNET_DEFAULT_POLL_INTERVAL;
1340
1341         if($last) {
1342                 $next = $last + ($poll_interval * 60);
1343                 if($next > time()) {
1344                         logger('appnet_cron: poll intervall not reached');
1345                         return;
1346                 }
1347         }
1348         logger('appnet_cron: cron_start');
1349
1350         $abandon_days = intval(get_config('system','account_abandon_days'));
1351         if ($abandon_days < 1)
1352                 $abandon_days = 0;
1353
1354         $abandon_limit = date("Y-m-d H:i:s", time() - $abandon_days * 86400);
1355
1356         $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'appnet' AND `k` = 'import' AND `v` = '1' ORDER BY RAND()");
1357         if(count($r)) {
1358                 foreach($r as $rr) {
1359                         if ($abandon_days != 0) {
1360                                 $user = q("SELECT `login_date` FROM `user` WHERE uid=%d AND `login_date` >= '%s'", $rr['uid'], $abandon_limit);
1361                                 if (!count($user)) {
1362                                         logger('abandoned account: timeline from user '.$rr['uid'].' will not be imported');
1363                                         continue;
1364                                 }
1365                         }
1366
1367                         logger('appnet_cron: importing timeline from user '.$rr['uid']);
1368                         appnet_fetchstream($a, $rr["uid"]);
1369                 }
1370         }
1371
1372         logger('appnet_cron: cron_end');
1373
1374         set_config('appnet','last_poll', time());
1375 }
1376
1377 function appnet_error($msg) {
1378         $msg = trim($msg);
1379         $pos = strrpos($msg, "\r\n\r\n");
1380
1381         if (!$pos)
1382                 return($msg);
1383
1384         $msg = substr($msg, $pos + 4);
1385
1386         $error = json_decode($msg);
1387
1388         if ($error == NULL)
1389                 return($msg);
1390
1391         if (isset($error->meta->error_message))
1392                 return($error->meta->error_message);
1393         else
1394                 return(print_r($error));
1395 }