]> git.mxchange.org Git - friendica-addons.git/commitdiff
Merge remote branch 'friendica/master'
authorfabrixxm <fabrix.xm@gmail.com>
Wed, 27 Feb 2013 09:33:53 +0000 (04:33 -0500)
committerfabrixxm <fabrix.xm@gmail.com>
Wed, 27 Feb 2013 09:33:53 +0000 (04:33 -0500)
165 files changed:
.gitignore [new file with mode: 0644]
INSTALL.txt [new file with mode: 0644]
altpager.tgz [new file with mode: 0644]
altpager/altpager.php
altpager/view/admin.tpl [new file with mode: 0644]
altpager/view/admin.tpl.old [new file with mode: 0755]
altpager/view/smarty3/admin.tpl [new file with mode: 0644]
blackout.tgz
blackout/admin.tpl [deleted file]
blackout/blackout.php
blackout/view/admin.tpl [new file with mode: 0644]
blackout/view/smarty3/admin.tpl [new file with mode: 0644]
buglink.tgz
buglink/buglink.php
communityhome.tgz
communityhome/README.md
communityhome/communityhome.css
communityhome/communityhome.php
communityhome/communityhome.tpl [deleted file]
communityhome/directory_item.tpl [deleted file]
communityhome/twillingham/README [deleted file]
communityhome/twillingham/communityhome.php [deleted file]
communityhome/view/communityhome.tpl [new file with mode: 0755]
communityhome/view/directory_item.tpl [new file with mode: 0755]
communityhome/view/smarty3/communityhome.tpl [new file with mode: 0644]
communityhome/view/smarty3/directory_item.tpl [new file with mode: 0644]
convert.tgz
curweather.tgz [new file with mode: 0644]
curweather/curweather.css [new file with mode: 0644]
curweather/curweather.php [new file with mode: 0644]
curweather/getweather.php [new file with mode: 0644]
curweather/test.php [new file with mode: 0644]
dav.tgz [new file with mode: 0644]
editplain.tgz
editplain/editplain.php
extcron.tgz
extcron/extcron.php
facebook.tgz
facebook/facebook.php
fbpost.tgz [new file with mode: 0644]
fbpost/README.md [new file with mode: 0644]
fbpost/fbpost.css [new file with mode: 0644]
fbpost/fbpost.php [new file with mode: 0644]
fortunate.tgz [new file with mode: 0644]
fortunate/README [new file with mode: 0644]
fortunate/cookie.php [new file with mode: 0644]
fortunate/fortunate.css [new file with mode: 0644]
fortunate/fortunate.php [new file with mode: 0644]
fortunate/fortunemod.sql.gz [new file with mode: 0644]
forumdirectory.tgz [new file with mode: 0644]
forumdirectory/forumdirectory.css [new file with mode: 0644]
forumdirectory/forumdirectory.php [new file with mode: 0644]
forumdirectory/view/forumdirectory_item.tpl [new file with mode: 0755]
forumdirectory/view/smarty3/forumdirectory_item.tpl [new file with mode: 0644]
forumlist.tgz [new file with mode: 0644]
forumlist/forumlist.css [new file with mode: 0644]
forumlist/forumlist.php [new file with mode: 0644]
fromapp.tgz [new file with mode: 0644]
fromapp/fromapp.css [new file with mode: 0644]
fromapp/fromapp.php [new file with mode: 0644]
fromgplus.tgz [new file with mode: 0644]
fromgplus/README
fromgplus/fromgplus.php
geonames.tgz
geonames/geonames.php
gravatar.tgz
gravatar/admin.tpl [deleted file]
gravatar/gravatar.php
gravatar/view/admin.tpl [new file with mode: 0644]
gravatar/view/smarty3/admin.tpl [new file with mode: 0644]
group_text.tgz [new file with mode: 0644]
group_text/group_text.php
impressum.tgz
impressum/admin.tpl [deleted file]
impressum/impressum.php
impressum/view/admin.tpl [new file with mode: 0644]
impressum/view/smarty3/admin.tpl [new file with mode: 0644]
jappixmini.tgz
js_upload.tgz
js_upload/js_upload.php
libravatar.tgz
libravatar/admin.tpl [deleted file]
libravatar/libravatar.php
libravatar/view/admin.tpl [new file with mode: 0644]
libravatar/view/smarty3/admin.tpl [new file with mode: 0644]
ljpost.tgz
ljpost/ljpost.css
mahjongg.tar [new file with mode: 0644]
mahjongg/mahjongg.php [new file with mode: 0755]
mahjongg/mahjongg.swf [new file with mode: 0755]
mathjax.tgz
mathjax/admin.tpl [deleted file]
mathjax/mathjax.php
mathjax/view/admin.tpl [new file with mode: 0644]
mathjax/view/smarty3/admin.tpl [new file with mode: 0644]
morepokes.tgz [new file with mode: 0644]
morepokes/morepokes.php
nsfw.tgz
nsfw/nsfw.php
openstreetmap.tgz
openstreetmap/admin.tpl [deleted file]
openstreetmap/openstreetmap.js [new file with mode: 0644]
openstreetmap/openstreetmap.php
openstreetmap/view/admin.tpl [new file with mode: 0644]
openstreetmap/view/smarty3/admin.tpl [new file with mode: 0644]
page.tgz
page/page.php
piwik.tgz
piwik/admin.tpl [deleted file]
piwik/piwik.php
piwik/view/admin.tpl [new file with mode: 0644]
piwik/view/smarty3/admin.tpl [new file with mode: 0644]
pledgie/pledgie.php [new file with mode: 0644]
privacy_image_cache.tgz
privacy_image_cache/privacy_image_cache.php
procrunner.tgz [new file with mode: 0644]
procrunner/procrunner.php [new file with mode: 0755]
randplace.tgz
remote_permissions.tgz [new file with mode: 0644]
remote_permissions/README.md [new file with mode: 0644]
remote_permissions/remote_permissions.php [new file with mode: 0644]
remote_permissions/settings.css [new file with mode: 0644]
remote_permissions/view/admin.tpl [new file with mode: 0644]
remote_permissions/view/settings.tpl [new file with mode: 0644]
remote_permissions/view/smarty3/admin.tpl [new file with mode: 0644]
remote_permissions/view/smarty3/settings.tpl [new file with mode: 0644]
rendertime/rendertime.php [new file with mode: 0755]
smiley_pack.tgz
smiley_pack/icons/food/birthdaycake.gif [new file with mode: 0644]
smiley_pack/smiley_pack.php
sniper.tgz
statusnet.tgz
statusnet/admin.tpl [deleted file]
statusnet/statusnet.css
statusnet/statusnet.php
statusnet/view/admin.tpl [new file with mode: 0644]
statusnet/view/smarty3/admin.tpl [new file with mode: 0644]
tumblr.tgz
tumblr/README [new file with mode: 0644]
tumblr/tumblr.php
tumblr/tumblroauth/OAuth.php [new file with mode: 0644]
tumblr/tumblroauth/tumblroauth.php [new file with mode: 0644]
twitter.tgz
twitter/README
twitter/admin.tpl [deleted file]
twitter/twitter.css
twitter/twitter.php
twitter/view/admin.tpl [new file with mode: 0644]
twitter/view/smarty3/admin.tpl [new file with mode: 0644]
uhremotestorage.tgz
uhremotestorage/settings.tpl [deleted file]
uhremotestorage/uhremotestorage.php
uhremotestorage/view/settings.tpl [new file with mode: 0644]
uhremotestorage/view/smarty3/settings.tpl [new file with mode: 0644]
viewsrc.tgz
viewsrc/viewsrc.php
widgets.tgz
widgets/settings.tpl [deleted file]
widgets/view/settings.tpl [new file with mode: 0755]
widgets/view/smarty3/settings.tpl [new file with mode: 0644]
widgets/view/smarty3/widget_like.tpl [new file with mode: 0644]
widgets/view/widget_like.tpl [new file with mode: 0755]
widgets/widget_like.php
widgets/widget_like.tpl [deleted file]
widgets/widgets.php

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..e185064
--- /dev/null
@@ -0,0 +1,24 @@
+favicon.*\r
+.htconfig.php\r
+\#*\r
+*.log\r
+*.out\r
+*.version*\r
+favicon.*\r
+*~\r
+\r
+#ignore reports, should be generted with every build\r
+report/\r
+\r
+#ignore config files from eclipse, we don't want IDE files in our repository\r
+.project\r
+.buildpath\r
+.externalToolBuilders\r
+.settings\r
+#ignore OSX .DS_Store files \r
+.DS_Store\r
+\r
+/nbproject/private/\r
+\r
+#ignore smarty cache\r
+/view/smarty3/compiled/
\ No newline at end of file
diff --git a/INSTALL.txt b/INSTALL.txt
new file mode 100644 (file)
index 0000000..ec9372e
--- /dev/null
@@ -0,0 +1,18 @@
+*********************
+* Install Using Git *
+*********************
+
+To install all addons using git, cd into your top level Friendica directory and
+
+git clone https://github.com/friendica/friendica-addons.git addon
+
+This will clone the entire repository in a directory called addon.  They can now be activated in the plugins section of your admin panel.
+
+********************
+* Install Manually *
+********************
+
+1. Download the archive (AddonName.tgz) containing the addon you want to install.
+2. Unzip the contents of the archive to your harddrive.
+3. Upload the extracted directory and all it's contents to /path/to/friendica/addon.  You will need to create the addon directory if this is the first addon you have installed.
+4. Activate the addon in the plugins section of your admin panel.
diff --git a/altpager.tgz b/altpager.tgz
new file mode 100644 (file)
index 0000000..fbfd559
Binary files /dev/null and b/altpager.tgz differ
index 65f9c0d835e1ccc90be2ca1b2598bdc83dc22c24..c6f537bd45aa785343350ae1f24173f3dc437621 100755 (executable)
@@ -61,6 +61,10 @@ function altpager_settings(&$a,&$s) {
        if(! local_user())
                return;
 
+       $global = get_config("alt_pager", "global");
+       if($global == 1)
+               return;
+
        /* Add our stylesheet to the page so we can make our settings look nice */
 
        $a->page['htmlhead'] .= '<link rel="stylesheet"  type="text/css" href="' . $a->get_baseurl() . '/addon/altpager/altpager.css' . '" media="all" />' . "\r\n";
@@ -87,3 +91,19 @@ function altpager_settings(&$a,&$s) {
        $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="altpager-submit" class="settings-submit" value="' . t('Submit') . '" /></div></div>';
 
 }
+
+function altpager_plugin_admin(&$a, &$o){
+       $t = get_markup_template( "admin.tpl", "addon/altpager/" );
+       $o = replace_macros($t, array(
+               '$submit' => t('Submit'),
+               '$global' => array('altpagerchoice', t('Global'), 1, t('Force global use of the alternate pager'),  get_config('alt_pager', 'global') == 1),
+               '$individual' => array('altpagerchoice', t('Individual'), 2, t('Each user chooses whether to use the alternate pager'),  get_config('alt_pager', 'global') == 0)
+       ));
+}
+
+function altpager_plugin_admin_post(&$a){
+       $choice =       ((x($_POST,'altpagerchoice'))           ? notags(trim($_POST['altpagerchoice']))        : '');
+       set_config('alt_pager','global',($choice == 1 ? 1 : 0));
+       info( t('Settings updated.'). EOL );
+}
+
diff --git a/altpager/view/admin.tpl b/altpager/view/admin.tpl
new file mode 100644 (file)
index 0000000..6055880
--- /dev/null
@@ -0,0 +1,3 @@
+{{ inc field_radio.tpl with $field=$global }}{{ endinc }}
+{{ inc field_radio.tpl with $field=$individual }}{{ endinc }}
+<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
diff --git a/altpager/view/admin.tpl.old b/altpager/view/admin.tpl.old
new file mode 100755 (executable)
index 0000000..6055880
--- /dev/null
@@ -0,0 +1,3 @@
+{{ inc field_radio.tpl with $field=$global }}{{ endinc }}
+{{ inc field_radio.tpl with $field=$individual }}{{ endinc }}
+<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
diff --git a/altpager/view/smarty3/admin.tpl b/altpager/view/smarty3/admin.tpl
new file mode 100644 (file)
index 0000000..e67afd7
--- /dev/null
@@ -0,0 +1,3 @@
+{{include file="field_radio.tpl" field=$global}}
+{{include file="field_radio.tpl" field=$individual}}
+<div class="submit"><input type="submit" name="page_site" value="{{$submit}}" /></div>
index 4b5a5d312d391537ef64ea909cf8ecdcffe15f0c..6d081dc4a55b5fdc050e9cb87f99d9a47af05ac8 100644 (file)
Binary files a/blackout.tgz and b/blackout.tgz differ
diff --git a/blackout/admin.tpl b/blackout/admin.tpl
deleted file mode 100644 (file)
index 2592219..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{{ inc field_input.tpl with $field=$startdate }}{{ endinc }}
-{{ inc field_input.tpl with $field=$enddate }}{{ endinc }}
-{{ inc field_input.tpl with $field=$rurl }}{{ endinc }}
-
-<div style="border: 2px solid #f00; padding: 10px; margin:
-10px;font-size: 1.2em;"><strong>Note</strong>: The redirect will be active from the moment you
-press the submit button. Users currently logged in will <strong>not</strong> be
-thrown out but can't login again after logging out should the blackout is
-still in place.</div>
-
-<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
index 2cb7c041d6cf3dff8f60486a10f2e4a4d879ffd4..834956114e4db95385b98e22603847d785ca645b 100644 (file)
@@ -93,8 +93,9 @@ function blackout_plugin_admin(&$a, &$o) {
     if (! is_string($myend)) { $myend = "YYYY-MM-DD:hhmm"; }
     $myurl   = get_config('blackout','url');
     if (! is_string($myurl)) { $myurl = "http://www.example.com"; }
-    $t = file_get_contents( dirname(__file__)."/admin.tpl" );
-    $o = replace_macros($t, array(
+    $t = get_markup_template( "admin.tpl", "addon/blackout/" );
+   $o = replace_macros($t, array(
         '$submit' => t('Submit'),
         '$rurl' => array("rurl", "Redirect URL", $myurl, "all your visitors from the web will be redirected to this URL"),
         '$startdate' => array("startdate", "Begin of the Blackout<br />(YYYY-MM-DD hh:mm)", $mystart, "format is <em>YYYY</em> year, <em>MM</em> month, <em>DD</em> day, <em>hh</em> hour and <em>mm</em> minute"),
diff --git a/blackout/view/admin.tpl b/blackout/view/admin.tpl
new file mode 100644 (file)
index 0000000..2592219
--- /dev/null
@@ -0,0 +1,11 @@
+{{ inc field_input.tpl with $field=$startdate }}{{ endinc }}
+{{ inc field_input.tpl with $field=$enddate }}{{ endinc }}
+{{ inc field_input.tpl with $field=$rurl }}{{ endinc }}
+
+<div style="border: 2px solid #f00; padding: 10px; margin:
+10px;font-size: 1.2em;"><strong>Note</strong>: The redirect will be active from the moment you
+press the submit button. Users currently logged in will <strong>not</strong> be
+thrown out but can't login again after logging out should the blackout is
+still in place.</div>
+
+<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
diff --git a/blackout/view/smarty3/admin.tpl b/blackout/view/smarty3/admin.tpl
new file mode 100644 (file)
index 0000000..11a4d91
--- /dev/null
@@ -0,0 +1,11 @@
+{{include file="field_input.tpl" field=$startdate}}
+{{include file="field_input.tpl" field=$enddate}}
+{{include file="field_input.tpl" field=$rurl}}
+
+<div style="border: 2px solid #f00; padding: 10px; margin:
+10px;font-size: 1.2em;"><strong>Note</strong>: The redirect will be active from the moment you
+press the submit button. Users currently logged in will <strong>not</strong> be
+thrown out but can't login again after logging out should the blackout is
+still in place.</div>
+
+<div class="submit"><input type="submit" name="page_site" value="{{$submit}}" /></div>
index 171a17e9c5c715619f7d220380f1dfdaca566ab9..f66558f24fa83be8abd8b86d27c2b59dd5339988 100755 (executable)
Binary files a/buglink.tgz and b/buglink.tgz differ
index faa97a0cdbba5a3a6618a5a76763da0f40f0ab59..9cd35ccdf2d5fda2719ab388d70fd672c8056f27 100755 (executable)
@@ -12,4 +12,4 @@ function buglink_install() { register_hook('page_end', 'addon/buglink/buglink.ph
 
 function buglink_uninstall() { unregister_hook('page_end', 'addon/buglink/buglink.php', 'buglink_active'); }
 
-function buglink_active(&$a,&$b) { $b .= '<div style="position: fixed; bottom: 5px; left: 5px;"><a href="http://bugs.friendica.com" title="' . t('Report Bug') . '"><img src="addon/buglink/bug-x.gif" alt="' . t('Report Bug') . '" /></a></div>'; } 
+function buglink_active(&$a,&$b) { $b .= '<div style="position: fixed; bottom: 5px; left: 5px;"><a href="http://bugs.friendica.com" target="_blank" title="' . t('Report Bug') . '"><img src="addon/buglink/bug-x.gif" alt="' . t('Report Bug') . '" /></a></div>'; } 
index 129081b613e8d3babac1e5ad3262e5558cf837c1..ab251425b711a5e6749dedbf1c4a8f56b036d49a 100755 (executable)
Binary files a/communityhome.tgz and b/communityhome.tgz differ
index 3cf610ec17689aad9f90f2de3bf267d3a9be6bd9..21f2a9465f97389ea0d36325c93721e3e72ccdfe 100755 (executable)
@@ -9,3 +9,26 @@ choosed to be in site directory), last ten public photos and last ten
 In main content is shown the community stream. This plugin doesn't 
 honour your community page visibility site setting: the community 
 stream is shown also if you have choose to not show the community page.
+
+If 'home.html' is found in your friendica root, its content is inserted 
+before community stream
+
+Each elements can be show or not. At the moment, there is no admin page
+for settings, so this settings must be added to yout .htconfig.php
+
+
+    $a->config['communityhome']['showcommunitystream'] = true;
+    $a->config['communityhome']['showlastlike'] = true;
+    $a->config['communityhome']['showlastphotos'] = true;
+    $a->config['communityhome']['showactiveusers'] = true;
+    $a->config['communityhome']['showlastusers'] = true;
+
+If you don't want to show something, set it to false.
+
+Note:
+-----
+
+- Default is "false". With no settings in .htconfig.php, nothing is 
+shown, except login form and content of 'home.html'
+
+- Active users query can be heavy for db, and on some system don't work
index 2efb6ebd50621dc99db5367a54cfb5cdc662c1e5..45a65537487994063ffab79fdcfe09ccb1c04cf0 100755 (executable)
@@ -39,4 +39,5 @@ aside .directory-photo-img { max-width: 48px; max-height: 48px; }
 aside #likes { margin: 0px; padding: 0px; list-style: none; }
 
 
-aside #login-extra-links { overflow: auto;     width: 100%; padding-top:120px;}
+aside #div_id_remember { overflow: auto;       width: 100%; padding-top:120px;}
+#login_openid input { width: 160px; }
index 2b14fd3381547eaa3da58f715836feb8976a8f4f..ba2af6de62bf36340a92ec9b8dd49bae2fdfd2cb 100755 (executable)
@@ -2,7 +2,7 @@
 /**
  * Name: Community home
  * Description: Show last community activity in homepage
- * Version: 1.0
+ * Version: 2.0
  * Author: Fabio Comuni <http://kirgroup.com/profile/fabrixxm>
  */
 
@@ -35,151 +35,166 @@ function communityhome_home(&$a, &$o){
        $aside['$login_form'] = login(($a->config['register_policy'] == REGISTER_CLOSED) ? false : true);
        
        // last 12 users
-       $aside['$lastusers_title'] = t('Latest users');
-       $aside['$lastusers_items'] = array();
-       $sql_extra = "";
-       $publish = (get_config('system','publish_all') ? '' : " AND `publish` = 1 " );
-       $order = " ORDER BY `register_date` DESC ";
+       if (get_config('communityhome','showlastusers')===true){
+               $aside['$lastusers_title'] = t('Latest users');
+               $aside['$lastusers_items'] = array();
+               $sql_extra = "";
+               $publish = (get_config('system','publish_all') ? '' : " AND `publish` = 1 " );
+               $order = " ORDER BY `register_date` DESC ";
 
-       $r = q("SELECT `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`
-                       FROM `profile` LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid` 
-                       WHERE `is-default` = 1 $publish AND `user`.`blocked` = 0 $sql_extra $order LIMIT %d , %d ",
-               0,
-               12
-       );
-       $tpl = file_get_contents( dirname(__file__).'/directory_item.tpl');
-       if(count($r)) {
-               $photo = 'thumb';
-               foreach($r as $rr) {
-                       $profile_link = $a->get_baseurl() . '/profile/' . ((strlen($rr['nickname'])) ? $rr['nickname'] : $rr['profile_uid']);
-                       $entry = replace_macros($tpl,array(
-                               '$id' => $rr['id'],
-                               '$profile-link' => $profile_link,
-                               '$photo' => $a->get_cached_avatar_image($rr[$photo]),
-                               '$alt-text' => $rr['name'],
-                       ));
-                       $aside['$lastusers_items'][] = $entry;
+               $r = q("SELECT `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`
+                               FROM `profile` LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid` 
+                               WHERE `is-default` = 1 $publish AND `user`.`blocked` = 0 $sql_extra $order LIMIT %d , %d ",
+                       0,
+                       12
+               );
+       #       $tpl = file_get_contents( dirname(__file__).'/directory_item.tpl');
+               $tpl = get_markup_template( 'directory_item.tpl', 'addon/communityhome/' );
+               if(count($r)) {
+                       $photo = 'thumb';
+                       foreach($r as $rr) {
+                               $profile_link = $a->get_baseurl() . '/profile/' . ((strlen($rr['nickname'])) ? $rr['nickname'] : $rr['profile_uid']);
+                               $entry = replace_macros($tpl,array(
+                                       '$id' => $rr['id'],
+                                       '$profile_link' => $profile_link,
+                                       '$photo' => $a->get_cached_avatar_image($rr[$photo]),
+                                       '$alt_text' => $rr['name'],
+                               ));
+                               $aside['$lastusers_items'][] = $entry;
+                       }
                }
        }
-       
        // 12 most active users (by posts and contacts)
        // this query don't work on some mysql versions
-       $r = q("SELECT `uni`.`contacts`,`uni`.`items`, `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`  FROM
-                       (SELECT COUNT(`id`) as `contacts`, `uid` FROM `contact` WHERE `self`=0 GROUP BY `uid`) AS `con`,
-                       (SELECT COUNT(`id`) as `items`, `uid` FROM `item` WHERE `item`.`changed` > DATE(NOW() - INTERVAL 1 MONTH) AND `item`.`wall` = 1 GROUP BY `uid`) AS `ite`,
-                       (
-                       SELECT `contacts`,`items`,`ite`.`uid` FROM `con` RIGHT OUTER JOIN `ite` ON `con`.`uid`=`ite`.`uid` 
-                       UNION ALL 
-                       SELECT `contacts`,`items`,`con`.`uid` FROM `con` LEFT OUTER JOIN `ite` ON `con`.`uid`=`ite`.`uid`
-                       ) AS `uni`, `user`, `profile`
-                       WHERE `uni`.`uid`=`user`.`uid`
-                       AND `uni`.`uid`=`profile`.`uid` AND `profile`.`publish`=1
-                       GROUP BY `uid`
-                       ORDER BY `items` DESC,`contacts` DESC
-                       LIMIT 0,10");
-       if($r && count($r)) {
-               $aside['$activeusers_title']  = t('Most active users');
-               $aside['$activeusers_items']  = array();
-               
-               $photo = 'thumb';
-               foreach($r as $rr) {
-                       $profile_link = $a->get_baseurl() . '/profile/' . ((strlen($rr['nickname'])) ? $rr['nickname'] : $rr['profile_uid']);
-                       $entry = replace_macros($tpl,array(
-                               '$id' => $rr['id'],
-                               '$profile-link' => $profile_link,
-                               '$photo' => $rr[$photo],
-                               '$alt-text' => sprintf("%s (%s posts, %s contacts)",$rr['name'], ($rr['items']?$rr['items']:'0'), ($rr['contacts']?$rr['contacts']:'0'))
-                       ));
-                       $aside['$activeusers_items'][] = $entry;
+       if (get_config('communityhome','showactiveusers')===true){
+               $r = q("SELECT `uni`.`contacts`,`uni`.`items`, `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`  FROM
+                               (SELECT COUNT(`id`) as `contacts`, `uid` FROM `contact` WHERE `self`=0 GROUP BY `uid`) AS `con`,
+                               (SELECT COUNT(`id`) as `items`, `uid` FROM `item` WHERE `item`.`changed` > DATE(NOW() - INTERVAL 1 MONTH) AND `item`.`wall` = 1 GROUP BY `uid`) AS `ite`,
+                               (
+                               SELECT `contacts`,`items`,`ite`.`uid` FROM `con` RIGHT OUTER JOIN `ite` ON `con`.`uid`=`ite`.`uid` 
+                               UNION ALL 
+                               SELECT `contacts`,`items`,`con`.`uid` FROM `con` LEFT OUTER JOIN `ite` ON `con`.`uid`=`ite`.`uid`
+                               ) AS `uni`, `user`, `profile`
+                               WHERE `uni`.`uid`=`user`.`uid`
+                               AND `uni`.`uid`=`profile`.`uid` AND `profile`.`publish`=1
+                               GROUP BY `uid`
+                               ORDER BY `items` DESC,`contacts` DESC
+                               LIMIT 0,10");
+               if($r && count($r)) {
+                       $aside['$activeusers_title']  = t('Most active users');
+                       $aside['$activeusers_items']  = array();
+                       
+                       $photo = 'thumb';
+                       foreach($r as $rr) {
+                               $profile_link = $a->get_baseurl() . '/profile/' . ((strlen($rr['nickname'])) ? $rr['nickname'] : $rr['profile_uid']);
+                               $entry = replace_macros($tpl,array(
+                                       '$id' => $rr['id'],
+                                       '$profile_link' => $profile_link,
+                                       '$photo' => $rr[$photo],
+                                       '$alt_text' => sprintf("%s (%s posts, %s contacts)",$rr['name'], ($rr['items']?$rr['items']:'0'), ($rr['contacts']?$rr['contacts']:'0'))
+                               ));
+                               $aside['$activeusers_items'][] = $entry;
+                       }
                }
        }
-       
        // last 12 photos
-       $aside['$photos_title'] = t('Latest photos');
-       $aside['$photos_items'] = array();
-       $r = q("SELECT `photo`.`id`, `photo`.`resource-id`, `photo`.`scale`, `photo`.`desc`, `user`.`nickname`, `user`.`username` FROM 
-                               (SELECT `resource-id`, MAX(`scale`) as maxscale FROM `photo` 
-                                       WHERE `profile`=0 AND `contact-id`=0 AND `album` NOT IN ('Contact Photos', '%s', 'Profile Photos', '%s')
-                                               AND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`='' GROUP BY `resource-id`) AS `t1`
-                               INNER JOIN `photo` ON `photo`.`resource-id`=`t1`.`resource-id` AND `photo`.`scale` = `t1`.`maxscale`,
-                               `user` 
-                               WHERE `user`.`uid` = `photo`.`uid`
-                               AND `user`.`blockwall`=0
-                               ORDER BY `photo`.`edited` DESC
-                               LIMIT 0, 12",
-                               dbesc(t('Contact Photos')),
-                               dbesc(t('Profile Photos'))
-                               );
+       if (get_config('communityhome','showlastphotos')===true){
+               $aside['$photos_title'] = t('Latest photos');
+               $aside['$photos_items'] = array();
+               $r = q("SELECT `photo`.`id`, `photo`.`resource-id`, `photo`.`scale`, `photo`.`desc`, `user`.`nickname`, `user`.`username` FROM 
+                                       (SELECT `resource-id`, MAX(`scale`) as maxscale FROM `photo` 
+                                               WHERE `profile`=0 AND `contact-id`=0 AND `album` NOT IN ('Contact Photos', '%s', 'Profile Photos', '%s')
+                                                       AND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`='' GROUP BY `resource-id`) AS `t1`
+                                       INNER JOIN `photo` ON `photo`.`resource-id`=`t1`.`resource-id` AND `photo`.`scale` = `t1`.`maxscale`,
+                                       `user` 
+                                       WHERE `user`.`uid` = `photo`.`uid`
+                                       AND `user`.`blockwall`=0
+                                       AND `user`.`hidewall` = 0
+                                       ORDER BY `photo`.`edited` DESC
+                                       LIMIT 0, 12",
+                                       dbesc(t('Contact Photos')),
+                                       dbesc(t('Profile Photos'))
+                                       );
 
-               
-       if(count($r)) {
-               $tpl = file_get_contents( dirname(__file__).'/directory_item.tpl');
-               foreach($r as $rr) {
-                       $photo_page = $a->get_baseurl() . '/photos/' . $rr['nickname'] . '/image/' . $rr['resource-id'];
-                       $photo_url = $a->get_baseurl() . '/photo/' .  $rr['resource-id'] . '-' . $rr['scale'] .'.jpg';
-               
-                       $entry = replace_macros($tpl,array(
-                               '$id' => $rr['id'],
-                               '$profile-link' => $photo_page,
-                               '$photo' => $photo_url,
-                               '$alt-text' => $rr['username']." : ".$rr['desc'],
-                       ));
+                       
+               if(count($r)) {
+       #               $tpl = file_get_contents( dirname(__file__).'/directory_item.tpl');
+                       $tpl = get_markup_template( 'directory_item.tpl', 'addon/communityhome/' );
+                       foreach($r as $rr) {
+                               $photo_page = $a->get_baseurl() . '/photos/' . $rr['nickname'] . '/image/' . $rr['resource-id'];
+                               $photo_url = $a->get_baseurl() . '/photo/' .  $rr['resource-id'] . '-' . $rr['scale'] .'.jpg';
+                       
+                               $entry = replace_macros($tpl,array(
+                                       '$id' => $rr['id'],
+                                       '$profile_link' => $photo_page,
+                                       '$photo' => $photo_url,
+                                       '$alt_text' => $rr['username']." : ".$rr['desc'],
+                               ));
 
-                       $aside['$photos_items'][] = $entry;
+                               $aside['$photos_items'][] = $entry;
+                       }
                }
        }
        
        // last 10 liked items
-       $aside['$like_title'] = t('Latest likes');
-       $aside['$like_items'] = array();
-       $r = q("SELECT `T1`.`created`, `T1`.`liker`, `T1`.`liker-link`, `item`.* FROM 
-                       (SELECT `parent-uri`, `created`, `author-name` AS `liker`,`author-link` AS `liker-link` 
-                               FROM `item` WHERE `verb`='http://activitystrea.ms/schema/1.0/like' GROUP BY `parent-uri` ORDER BY `created` DESC) AS T1
-                       INNER JOIN `item` ON `item`.`uri`=`T1`.`parent-uri` 
-                       WHERE `T1`.`liker-link` LIKE '%s%%' OR `item`.`author-link` LIKE '%s%%'
-                       GROUP BY `uri`
-                       ORDER BY `T1`.`created` DESC
-                       LIMIT 0,10",
-                       $a->get_baseurl(),$a->get_baseurl()
-                       );
+       if (get_config('communityhome','showlastlike')===true){
+               $aside['$like_title'] = t('Latest likes');
+               $aside['$like_items'] = array();
+               $r = q("SELECT `T1`.`created`, `T1`.`liker`, `T1`.`liker-link`, `item`.* FROM 
+                               (SELECT `parent-uri`, `created`, `author-name` AS `liker`,`author-link` AS `liker-link` 
+                                       FROM `item` WHERE `verb`='http://activitystrea.ms/schema/1.0/like' GROUP BY `parent-uri` ORDER BY `created` DESC) AS T1
+                               INNER JOIN `item` ON `item`.`uri`=`T1`.`parent-uri` 
+                               WHERE `T1`.`liker-link` LIKE '%s%%' OR `item`.`author-link` LIKE '%s%%'
+                               GROUP BY `uri`
+                               ORDER BY `T1`.`created` DESC
+                               LIMIT 0,10",
+                               $a->get_baseurl(),$a->get_baseurl()
+                               );
 
-       foreach ($r as $rr) {
-               $author  = '<a href="' . $rr['liker-link'] . '">' . $rr['liker'] . '</a>';
-               $objauthor =  '<a href="' . $rr['author-link'] . '">' . $rr['author-name'] . '</a>';
-               
-               //var_dump($rr['verb'],$rr['object-type']); killme();
-               switch($rr['verb']){
-                       case 'http://activitystrea.ms/schema/1.0/post':
-                               switch ($rr['object-type']){
-                                       case 'http://activitystrea.ms/schema/1.0/event':
-                                               $post_type = t('event');
-                                               break;
-                                       default:
+               foreach ($r as $rr) {
+                       $author  = '<a href="' . $rr['liker-link'] . '">' . $rr['liker'] . '</a>';
+                       $objauthor =  '<a href="' . $rr['author-link'] . '">' . $rr['author-name'] . '</a>';
+                       
+                       //var_dump($rr['verb'],$rr['object-type']); killme();
+                       switch($rr['verb']){
+                               case 'http://activitystrea.ms/schema/1.0/post':
+                                       switch ($rr['object-type']){
+                                               case 'http://activitystrea.ms/schema/1.0/event':
+                                                       $post_type = t('event');
+                                                       break;
+                                               default:
+                                                       $post_type = t('status');
+                                       }
+                                       break;
+                               default:
+                                       if ($rr['resource-id']){
+                                               $post_type = t('photo');
+                                               $m=array();     preg_match("/\[url=([^]]*)\]/", $rr['body'], $m);
+                                               $rr['plink'] = $m[1];
+                                       } else {
                                                $post_type = t('status');
-                               }
-                               break;
-                       default:
-                               if ($rr['resource-id']){
-                                       $post_type = t('photo');
-                                       $m=array();     preg_match("/\[url=([^]]*)\]/", $rr['body'], $m);
-                                       $rr['plink'] = $m[1];
-                               } else {
-                                       $post_type = t('status');
-                               }
-               }
-               $plink = '<a href="' . $rr['plink'] . '">' . $post_type . '</a>';
+                                       }
+                       }
+                       $plink = '<a href="' . $rr['plink'] . '">' . $post_type . '</a>';
 
-               $aside['$like_items'][] = sprintf( t('%1$s likes %2$s\'s %3$s'), $author, $objauthor, $plink);
-               
+                       $aside['$like_items'][] = sprintf( t('%1$s likes %2$s\'s %3$s'), $author, $objauthor, $plink);
+                       
+               }
        }
        
-       $tpl = file_get_contents(dirname(__file__).'/communityhome.tpl');
+#      $tpl = file_get_contents(dirname(__file__).'/communityhome.tpl');
+       $tpl = get_markup_template('communityhome.tpl', 'addon/communityhome/');
        $a->page['aside'] = replace_macros($tpl, $aside);
        
        $o = '<h1>' . ((x($a->config,'sitename')) ? sprintf( t("Welcome to %s") ,$a->config['sitename']) : "" ) . '</h1>';
        
-       $oldset = get_config('system','no_community_page');
-       set_config('system','no_community_page', false);
-       $o .= community_content($a,1);
-       set_config('system','no_community_page', $oldset);
+       if(file_exists('home.html'))
+               $o = file_get_contents('home.html');
+       
+       if (get_config('communityhome','showcommunitystream')===true){
+               $oldset = get_config('system','no_community_page');
+               set_config('system','no_community_page', false);
+               $o .= community_content($a,1);
+               set_config('system','no_community_page', $oldset);
+       }
 }
diff --git a/communityhome/communityhome.tpl b/communityhome/communityhome.tpl
deleted file mode 100755 (executable)
index 8468780..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-<script>
-       $(function(){
-               $("#tab_1 a").click(function(e){
-                       $("#login_standard").show();
-                       $("#login_openid").hide();
-                       $("#tab_1").addClass("active");
-                       $("#tab_2").removeClass("active");
-                       e.preventDefault();
-                       return false;
-               });
-               $("#tab_2 a").click(function(e){
-                       $("#login_openid").show();
-                       $("#login_standard").hide();
-                       $("#tab_2").addClass("active");
-                       $("#tab_1").removeClass("active");
-                       e.preventDefault();
-                       return false;
-                       
-               });
-               
-       });
-</script>
-{{ if $noOid }}
-       <h3>$login_title</h3>
-{{ else }}
-<ul class="tabs">
-       <li id="tab_1" class="tab button active"><a href="#">$tab_1</a></li>
-       <li id="tab_2" class="tab button"><a href="#">$tab_2</a></li>
-</ul>
-{{ endif }}
-$login_form
-
-
-{{ if $lastusers_title }}
-<h3>$lastusers_title</h3>
-<div class='items-wrapper'>
-{{ for $lastusers_items as $i }}
-       $i
-{{ endfor }}
-</div>
-{{ endif }}
-
-
-{{ if $activeusers_title }}
-<h3>$activeusers_title</h3>
-<div class='items-wrapper'>
-{{ for $activeusers_items as $i }}
-       $i
-{{ endfor }}
-</div>
-{{ endif }}
-
-{{ if $photos_title }}
-<h3>$photos_title</h3>
-<div class='items-wrapper'>
-{{ for $photos_items as $i }}
-       $i
-{{ endfor }}
-</div>
-{{ endif }}
-
-
-{{ if $like_title }}
-<h3>$like_title</h3>
-<ul id='likes'>
-{{ for $like_items as $i }}
-       <li>$i</li>
-{{ endfor }}
-</ul>
-{{ endif }}
diff --git a/communityhome/directory_item.tpl b/communityhome/directory_item.tpl
deleted file mode 100755 (executable)
index db1936e..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-
-<div class="directory-item" id="directory-item-$id" >
-       <div class="directory-photo-wrapper" id="directory-photo-wrapper-$id" > 
-               <div class="directory-photo" id="directory-photo-$id" >
-                       <a href="$profile-link" class="directory-profile-link" id="directory-profile-link-$id" >
-                               <img class="directory-photo-img" src="$photo" alt="$alt-text" title="$alt-text" />
-                       </a>
-               </div>
-       </div>
-</div>
diff --git a/communityhome/twillingham/README b/communityhome/twillingham/README
deleted file mode 100644 (file)
index dbbe141..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-This is a variant of the community home.  Instead of displaying the community tab in the front page, we still use home.html, but we also add the latest users to the sidebar.
-
-Simply replace addon/communityhome/communityhome.php with this version then enable community home in your admin panel as usual.
\ No newline at end of file
diff --git a/communityhome/twillingham/communityhome.php b/communityhome/twillingham/communityhome.php
deleted file mode 100644 (file)
index 102732a..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-/**
- * Name: Community home
- * Description: Show last community activity in homepage
- * Version: 1.0
- * Author: Fabio Comuni <http://kirgroup.com/profile/fabrixxm>
- */
-
-
-require_once('mod/community.php');
-
-
-function communityhome_install() {
-       register_hook('home_content', 'addon/communityhome/communityhome.php', 'communityhome_home');
-       logger("installed communityhome");
-}
-
-function communityhome_uninstall() {
-       unregister_hook('home_content', 'addon/communityhome/communityhome.php', 'communityhome_home');
-       logger("removed communityhome");
-}
-
-function communityhome_home(&$a, &$o){
-       // custom css
-       $a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="'.$a->get_baseurl().'/addon/communityhome/communityhome.css" media="all" />';
-       
-       $aside = array(
-               '$tab_1' => t('Login'),
-               '$tab_2' => t('OpenID'),
-               '$noOid' => get_config('system','no_openid'),
-       );
-       
-       // login form
-       $aside['$login_title'] =  t('Login');
-       $aside['$login_form'] = login(($a->config['register_policy'] == REGISTER_CLOSED) ? false : true);
-       
-       // last 12 users
-       $aside['$lastusers_title'] = t('Latest users');
-       $aside['$lastusers_items'] = array();
-       $sql_extra = "";
-       $publish = (get_config('system','publish_all') ? '' : " AND `publish` = 1 " );
-       $order = " ORDER BY `register_date` DESC ";
-
-       $r = q("SELECT `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`
-                       FROM `profile` LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid` 
-                       WHERE `is-default` = 1 $publish AND `user`.`blocked` = 0 $sql_extra $order LIMIT %d , %d ",
-               0,
-               12
-       );
-       $tpl = file_get_contents( dirname(__file__).'/directory_item.tpl');
-       if(count($r)) {
-               $photo = 'thumb';
-               foreach($r as $rr) {
-                       $profile_link = $a->get_baseurl() . '/profile/' . ((strlen($rr['nickname'])) ? $rr['nickname'] : $rr['profile_uid']);
-                       $entry = replace_macros($tpl,array(
-                               '$id' => $rr['id'],
-                               '$profile-link' => $profile_link,
-                               '$photo' => $rr[$photo],
-                               '$alt-text' => $rr['name'],
-                       ));
-                       $aside['$lastusers_items'][] = $entry;
-               }
-       }
-       
-       // 12 most active users (by posts and contacts)
-       // this query don't work on some mysql versions
-       $r = q("SELECT `uni`.`contacts`,`uni`.`items`, `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`  FROM
-                       (SELECT COUNT(`id`) as `contacts`, `uid` FROM `contact` WHERE `self`=0 GROUP BY `uid`) AS `con`,
-                       (SELECT COUNT(`id`) as `items`, `uid` FROM `item` WHERE `item`.`changed` > DATE(NOW() - INTERVAL 1 MONTH) AND `item`.`wall` = 1 GROUP BY `uid`) AS `ite`,
-                       (
-                       SELECT `contacts`,`items`,`ite`.`uid` FROM `con` RIGHT OUTER JOIN `ite` ON `con`.`uid`=`ite`.`uid` 
-                       UNION ALL 
-                       SELECT `contacts`,`items`,`con`.`uid` FROM `con` LEFT OUTER JOIN `ite` ON `con`.`uid`=`ite`.`uid`
-                       ) AS `uni`, `user`, `profile`
-                       WHERE `uni`.`uid`=`user`.`uid`
-                       AND `uni`.`uid`=`profile`.`uid` AND `profile`.`publish`=1
-                       GROUP BY `uid`
-                       ORDER BY `items` DESC,`contacts` DESC
-                       LIMIT 0,10");
-       if($r && count($r)) {
-               $aside['$activeusers_title']  = t('Most active users');
-               $aside['$activeusers_items']  = array();
-               
-               $photo = 'thumb';
-               foreach($r as $rr) {
-                       $profile_link = $a->get_baseurl() . '/profile/' . ((strlen($rr['nickname'])) ? $rr['nickname'] : $rr['profile_uid']);
-                       $entry = replace_macros($tpl,array(
-                               '$id' => $rr['id'],
-                               '$profile-link' => $profile_link,
-                               '$photo' => $rr[$photo],
-                               '$alt-text' => sprintf("%s (%s posts, %s contacts)",$rr['name'], ($rr['items']?$rr['items']:'0'), ($rr['contacts']?$rr['contacts']:'0'))
-                       ));
-                       $aside['$activeusers_items'][] = $entry;
-               }
-       }
-       
-       
-       
-       
-       $tpl = file_get_contents(dirname(__file__).'/communityhome.tpl');
-       $a->page['aside'] = replace_macros($tpl, $aside);
-       $o = '';
-       if(file_exists('home.html'))
-       
-               $o .= file_get_contents('home.html');
-       
-}
diff --git a/communityhome/view/communityhome.tpl b/communityhome/view/communityhome.tpl
new file mode 100755 (executable)
index 0000000..8468780
--- /dev/null
@@ -0,0 +1,70 @@
+<script>
+       $(function(){
+               $("#tab_1 a").click(function(e){
+                       $("#login_standard").show();
+                       $("#login_openid").hide();
+                       $("#tab_1").addClass("active");
+                       $("#tab_2").removeClass("active");
+                       e.preventDefault();
+                       return false;
+               });
+               $("#tab_2 a").click(function(e){
+                       $("#login_openid").show();
+                       $("#login_standard").hide();
+                       $("#tab_2").addClass("active");
+                       $("#tab_1").removeClass("active");
+                       e.preventDefault();
+                       return false;
+                       
+               });
+               
+       });
+</script>
+{{ if $noOid }}
+       <h3>$login_title</h3>
+{{ else }}
+<ul class="tabs">
+       <li id="tab_1" class="tab button active"><a href="#">$tab_1</a></li>
+       <li id="tab_2" class="tab button"><a href="#">$tab_2</a></li>
+</ul>
+{{ endif }}
+$login_form
+
+
+{{ if $lastusers_title }}
+<h3>$lastusers_title</h3>
+<div class='items-wrapper'>
+{{ for $lastusers_items as $i }}
+       $i
+{{ endfor }}
+</div>
+{{ endif }}
+
+
+{{ if $activeusers_title }}
+<h3>$activeusers_title</h3>
+<div class='items-wrapper'>
+{{ for $activeusers_items as $i }}
+       $i
+{{ endfor }}
+</div>
+{{ endif }}
+
+{{ if $photos_title }}
+<h3>$photos_title</h3>
+<div class='items-wrapper'>
+{{ for $photos_items as $i }}
+       $i
+{{ endfor }}
+</div>
+{{ endif }}
+
+
+{{ if $like_title }}
+<h3>$like_title</h3>
+<ul id='likes'>
+{{ for $like_items as $i }}
+       <li>$i</li>
+{{ endfor }}
+</ul>
+{{ endif }}
diff --git a/communityhome/view/directory_item.tpl b/communityhome/view/directory_item.tpl
new file mode 100755 (executable)
index 0000000..f32f5a4
--- /dev/null
@@ -0,0 +1,10 @@
+
+<div class="directory-item" id="directory-item-$id" >
+       <div class="directory-photo-wrapper" id="directory-photo-wrapper-$id" > 
+               <div class="directory-photo" id="directory-photo-$id" >
+                       <a href="$profile_link" class="directory-profile-link" id="directory-profile-link-$id" >
+                               <img class="directory-photo-img" src="$photo" alt="$alt_text" title="$alt_text" />
+                       </a>
+               </div>
+       </div>
+</div>
diff --git a/communityhome/view/smarty3/communityhome.tpl b/communityhome/view/smarty3/communityhome.tpl
new file mode 100644 (file)
index 0000000..b8f8038
--- /dev/null
@@ -0,0 +1,70 @@
+<script>
+       $(function(){
+               $("#tab_1 a").click(function(e){
+                       $("#login_standard").show();
+                       $("#login_openid").hide();
+                       $("#tab_1").addClass("active");
+                       $("#tab_2").removeClass("active");
+                       e.preventDefault();
+                       return false;
+               });
+               $("#tab_2 a").click(function(e){
+                       $("#login_openid").show();
+                       $("#login_standard").hide();
+                       $("#tab_2").addClass("active");
+                       $("#tab_1").removeClass("active");
+                       e.preventDefault();
+                       return false;
+                       
+               });
+               
+       });
+</script>
+{{if $noOid}}
+       <h3>{{$login_title}}</h3>
+{{else}}
+<ul class="tabs">
+       <li id="tab_1" class="tab button active"><a href="#">{{$tab_1}}</a></li>
+       <li id="tab_2" class="tab button"><a href="#">{{$tab_2}}</a></li>
+</ul>
+{{/if}}
+{{$login_form}}
+
+
+{{if $lastusers_title}}
+<h3>{{$lastusers_title}}</h3>
+<div class='items-wrapper'>
+{{foreach $lastusers_items as $i}}
+       {{$i}}
+{{/foreach}}
+</div>
+{{/if}}
+
+
+{{if $activeusers_title}}
+<h3>{{$activeusers_title}}</h3>
+<div class='items-wrapper'>
+{{foreach $activeusers_items as $i}}
+       {{$i}}
+{{/foreach}}
+</div>
+{{/if}}
+
+{{if $photos_title}}
+<h3>{{$photos_title}}</h3>
+<div class='items-wrapper'>
+{{foreach $photos_items as $i}}
+       {{$i}}
+{{/foreach}}
+</div>
+{{/if}}
+
+
+{{if $like_title}}
+<h3>{{$like_title}}</h3>
+<ul id='likes'>
+{{foreach $like_items as $i}}
+       <li>{{$i}}</li>
+{{/foreach}}
+</ul>
+{{/if}}
diff --git a/communityhome/view/smarty3/directory_item.tpl b/communityhome/view/smarty3/directory_item.tpl
new file mode 100644 (file)
index 0000000..5fb1198
--- /dev/null
@@ -0,0 +1,10 @@
+
+<div class="directory-item" id="directory-item-{{$id}}" >
+       <div class="directory-photo-wrapper" id="directory-photo-wrapper-{{$id}}" > 
+               <div class="directory-photo" id="directory-photo-{{$id}}" >
+                       <a href="{{$profile}}-link" class="directory-profile-link" id="directory-profile-link-{{$id}}" >
+                               <img class="directory-photo-img" src="{{$photo}}" alt="{{$alt}}-text" title="{{$alt}}-text" />
+                       </a>
+               </div>
+       </div>
+</div>
index 56e0080c36b9c959832c7d441e7fa1117f42edba..766eaf7aa41c9aa30835a773b68065c4f1e1829c 100755 (executable)
Binary files a/convert.tgz and b/convert.tgz differ
diff --git a/curweather.tgz b/curweather.tgz
new file mode 100644 (file)
index 0000000..76e0646
Binary files /dev/null and b/curweather.tgz differ
diff --git a/curweather/curweather.css b/curweather/curweather.css
new file mode 100644 (file)
index 0000000..6c12796
--- /dev/null
@@ -0,0 +1,10 @@
+
+#curtemp-settings-label, #curtemp-location-label, #curtemp-enable-label {
+       float: left;
+       width: 200px;
+       margin-bottom: 25px;
+}
+#curtemp-network {
+       float: left;
+}
+
diff --git a/curweather/curweather.php b/curweather/curweather.php
new file mode 100644 (file)
index 0000000..c935eb5
--- /dev/null
@@ -0,0 +1,108 @@
+       <?php
+/**
+ * Name: Current Weather 
+ * Description: Shows current weather conditions for user's location on their network page.<br />Find the location code for the station or airport nearest you <a href="http://en.wikipedia.org/wiki/International_Air_Transport_Association_airport_code" target="_blank">here</a>.
+ * Version: 1.0
+ * Author: Tony Baldwin <http://friendica.tonybaldwin.info/u/t0ny>
+ * Author: Fabio Comuni <http://kirkgroup.com/u/fabrixxm>
+ *
+ */
+require_once('addon/curweather/getweather.php');
+
+function curweather_install() {
+       register_hook('network_mod_init', 'addon/curweather/curweather.php', 'curweather_network_mod_init');
+       register_hook('plugin_settings', 'addon/curweather/curweather.php', 'curweather_plugin_settings');
+       register_hook('plugin_settings_post', 'addon/curweather/curweather.php', 'curweather_plugin_settings_post');
+
+}
+
+function curweather_uninstall() {
+       unregister_hook('network_mod_init', 'addon/curweather/curweather.php', 'curweather_network_mod_init');
+       unregister_hook('plugin_settings', 'addon/curweather/curweather.php', 'curweather_plugin_settings');
+       unregister_hook('plugin_settings_post', 'addon/curweather/curweather.php', 'curweather_plugin_settings_post');
+
+}
+
+
+function curweather_network_mod_init(&$fk_app,&$b) {
+
+    if(! intval(get_pconfig(local_user(),'curweather','curweather_enable')))
+        return;
+
+    $fk_app->page['htmlhead'] .= '<link rel="stylesheet"  type="text/css" href="' . $fk_app->get_baseurl() . '/addon/curweather/curweather.css' . '" media="all" />' . "\r\n";
+
+    // the getweather file does all the work here
+    // the $rpt value is needed for location
+    // which getweather uses to fetch the weather data for weather and temp
+    $rpt = get_pconfig(local_user(), 'curweather', 'curweather_loc');
+    $wxdata = GetWeather::get($rpt);
+    $temp = $wxdata['TEMPERATURE_STRING'];
+    $weather = $wxdata['WEATHER'];
+    $rhumid = $wxdata['RELATIVE_HUMIDITY'];
+    $pressure = $wxdata['PRESSURE_STRING'];
+    $wind = $wxdata['WIND_STRING'];
+    $curweather = '<div id="curweather-network" class="widget">
+                <div class="title tool">
+                <h4>'.t("Current Weather").'</h4></div>';
+
+    $curweather .= "Weather: $weather<br />
+                 Temperature: $temp<br />
+                Relative Humidity: $rhumid<br />
+                Pressure: $pressure<br />
+                Wind: $wind";
+
+    $curweather .= '</div><div class="clear"></div>';
+
+    $fk_app->page['aside'] = $curweather.$fk_app->page['aside'];
+
+}
+
+
+function curweather_plugin_settings_post($a,$post) {
+       if(! local_user() || (! x($_POST,'curweather-settings-submit')))
+               return;
+       set_pconfig(local_user(),'curweather','curweather_loc',trim($_POST['curweather_loc']));
+       set_pconfig(local_user(),'curweather','curweather_enable',intval($_POST['curweather_enable']));
+
+       info( t('Current Weather settings updated.') . EOL);
+}
+
+
+function curweather_plugin_settings(&$a,&$s) {
+
+       if(! local_user())
+               return;
+
+       /* Add our stylesheet to the curweather so we can make our settings look nice */
+
+       $a->page['htmlhead'] .= '<link rel="stylesheet"  type="text/css" href="' . $a->get_baseurl() . '/addon/curweather/curweather.css' . '" media="all" />' . "\r\n";
+
+       /* Get the current state of our config variable */
+
+       $curweather_loc = get_pconfig(local_user(), 'curweather', 'curweather_loc');
+       $enable = intval(get_pconfig(local_user(),'curweather','curweather_enable'));
+       $enable_checked = (($enable) ? ' checked="checked" ' : '');
+       
+       
+       /* Add some HTML to the existing form */
+
+       $s .= '<div class="settings-block">';
+       $s .= '<h3>' . t('Current Weather Settings') . '</h3>';
+       $s .= '<div id="curweather-settings-wrapper">';
+       $s .= '<p>Find the location code for the airport/weather station nearest you <a href="http://en.wikipedia.org/wiki/International_Air_Transport_Association_airport_code" target="_blank">here</a>.</p>';
+       $s .= '<label id="curweather-location-label" for="curweather_loc">' . t('Weather Location: ') . '</label>';
+       $s .= '<input id="curweather-location" type="text" name="curweather_loc" value="' . $curweather_loc . '"/>';
+       $s .= '<div class="clear"></div>';
+       $s .= '<label id="curweather-enable-label" for="curweather_enable">' . t('Enable Current Weather') . '</label>';
+       $s .= '<input id="curweather-enable" type="checkbox" name="curweather_enable" value="1" ' . $enable_checked . '/>';
+       $s .= '<div class="clear"></div>';
+
+       $s .= '</div>';
+
+       /* provide a submit button */
+
+       $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="curweather-settings-submit" class="settings-submit" value="' . t('Submit') . '" /></div></div>';
+
+}
+
+
diff --git a/curweather/getweather.php b/curweather/getweather.php
new file mode 100644 (file)
index 0000000..b4660b9
--- /dev/null
@@ -0,0 +1,230 @@
+<?php
+/*
+File Name: getweather.php
+Author: Gary White
+Original version: May 12, 2005
+Last modified: August 7, 2008
+
+Copyright (C) 2004-2008 Gary White
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License in the included gpl.txt file for
+details.
+
+See http://apptools.com/phptools/xml/weather/ for usage information
+
+See http://weather.gov/data/current_obs/
+Also see 
+       http://weather.gov/alerts/
+       http://weather.gov/forecasts/xml/
+
+Complete list of Weather stations available at 
+       http://weather.gov/data/current_obs/index.xml
+
+*/
+class GetWeather {
+
+    // Initialize some variables
+    static $itemdata;
+    static $itemname;
+    static $wxdata;
+
+
+    function get($rpt) {
+        
+        // URL for the XML file
+        $xmlurl="http://www.weather.gov/data/current_obs/$rpt.xml";
+
+        // Base url for the icons
+        $imgpath="http://weather.gov/weather/images/fcicons";
+
+        
+        self::$itemdata="";
+        self::$itemname="";
+        self::$wxdata=array();
+  
+        $icons=self::defineIcons();
+        $icon="";
+        $data="";
+        $report="";
+        
+        // create a new CURL resource
+        if($ch = curl_init()) {
+
+            // set URL and other appropriate options
+            curl_setopt($ch, CURLOPT_URL, $xmlurl);
+            curl_setopt($ch, CURLOPT_HEADER, trus);
+            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+            
+            // grab URL and pass it to the browser
+            $data=curl_exec($ch);
+
+            $r=curl_getinfo($ch); //,CURLINFO_HTTP_CODE);
+
+            // close CURL resource, and free up system resources
+            curl_close($ch);
+
+            // Create an XML parser
+            $xml_parser = xml_parser_create();
+            
+            // Use case-folding so we are sure to find the tag in $map_array
+            // This will force all tags to upper case so we don't have to worry
+            // about matching the case of the original in our tests.
+            xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, true);
+            
+            // Assign the element starting and ending event handlers
+            xml_set_element_handler($xml_parser, array(self,"startElement"), array(self,"endElement"));
+            
+            // Assign a function to handle character data
+            xml_set_character_data_handler($xml_parser, array(self,"characterData"));
+            
+            // Parse the file. This will place the data into an associative
+            // array assigned to the self::$wxdata variable
+            xml_parse($xml_parser,$data,true);
+            
+            // Free the parser object
+            xml_parser_free($xml_parser);
+            
+            // The OBSERVATION_TIME field of the returned XML will be in the
+            // format "Last Updated on May 18, 8:53 am CDT"
+            // We're going to change the format a bit.
+
+            // Strip out the "Last Updated on " portion of the date/time
+            // so we can display that separately in our tabular output
+            $datetime=str_replace("Last Updated on ","",self::$wxdata['OBSERVATION_TIME']);
+            
+            // We now have the format as "May 18, 8:53 am CDT"
+            // Now, get the time zone. It will be everything from
+            // the last space character to the end of the string.
+            $z=strrchr($datetime," ");
+
+            // Get the current year
+            $year=date("Y");
+
+            // Now, we stuff the year into the string, following the comma.
+            $datetime=str_replace(",",", $year",$datetime);
+
+            // This does leave a small potential issue where, if you get a 
+            // report between midnight and 1 a.m. on January 1, or the server
+            // is in a significantly different time zone than the report it 
+            // could be as late as 4 a.m. the year will be wrong because the 
+            // report will be from the previous year. I suppose it would be 
+            // possible to correct for that, but for that little bit, I'm 
+            // not going to worry about it.
+
+            // Now, strip out the time zone
+            $datetime=str_replace($z,"",$datetime);
+
+            // Format the date and time the way we want it and add
+            // back the time zone
+            $datetime=date("l F j, Y g:i A",strtotime($datetime)).$z;
+            self::$wxdata['OBSERVATION_TIME']=$datetime;
+            
+            // Get the WEATHER element
+            $wx=trim(self::$wxdata['WEATHER']);
+
+            // Now, get the icon to match the weather
+            foreach($icons as $k=>$i){
+                $a=explode(" | ",$i);
+                if(is_numeric(array_search($wx,$a))){
+                    self::$wxdata['ICON']="$imgpath/$k.jpg";
+                    break;
+                }
+            }
+
+            // Replace any null elements with "Not available"
+            foreach(array_keys(self::$wxdata) as $key){
+                self::$wxdata[$key]=self::$wxdata[$key]=="NULL"?"Not available":self::$wxdata[$key];
+            }
+
+            // If we got humidity
+            if(is_numeric(self::$wxdata['RELATIVE_HUMIDITY']))
+                // Append a percent sign
+                self::$wxdata['RELATIVE_HUMIDITY'].="%";
+
+            // Do some formatting to make the output a little friendlier
+            if(self::$wxdata['VISIBILITY_MI']=="NA")
+                self::$wxdata['VISIBILITY']="Not available";
+            if(self::$wxdata['VISIBILITY']!="Not available")
+                self::$wxdata['VISIBILITY']=(1*self::$wxdata['VISIBILITY_MI'])." miles";
+
+            // If we got wind data
+            if(is_numeric(self::$wxdata['WIND_MPH'])){
+                // We're going to output wind data as both MPH from a cardinal direction
+                // and as Knots from a direction in degrees
+
+                // Calculate the value for Knots
+                self::$wxdata['WIND_KNOTS']=self::$wxdata['WIND_MPH']/1.15;
+
+                // Format the output
+                $wind=sprintf("From the %s at %d mph (%03.0f&deg; at %d knots)",self::$wxdata['WIND_DIR'],self::$wxdata['WIND_MPH'],self::$wxdata['WIND_DEGREES'],self::$wxdata['WIND_KNOTS']);
+
+                // If we got a value for wind gusts
+                if(is_numeric(self::$wxdata['WIND_GUST_MPH']) && self::$wxdata['WIND_GUST_MPH']>0){
+                    // add it into the wind string
+                    $wind=str_replace("mph","gusting to ".self::$wxdata['WIND_GUST_MPH']." mph<br>", $wind);
+                    $knots=sprintf("%d",self::$wxdata['WIND_GUST_MPH']/1.15);
+                    $wind=str_replace("knots","gusting to $knots knots",$wind);
+                }
+            } else {
+                // Otherwise, if wind is zero, we'll show "Calm"
+                $wind=self::$wxdata['WIND_MPH']=="Not available"?"Not available":"Calm";
+            } // Done with wind
+            self::$wxdata['WIND_STRING']=$wind;
+
+        } // Done getting and formatting the data
+        return self::$wxdata;
+    }
+    
+    function startElement($parser, $name, $attrs) {
+        self::$itemname=$name;
+        self::$itemdata="";
+    }
+
+    function endElement($parser, $name) {
+        self::$wxdata[self::$itemname]=self::$itemdata;
+        self::$itemdata="";
+    }
+
+    function characterData($parser, $data) {
+        self::$itemdata.=$data;
+    }
+
+    function defineIcons(){
+        // See http://weather.gov/data/current_obs/weather.php for source data for this function
+        $retVal['bkn']="Mostly Cloudy | Mostly Cloudy with Haze | Mostly Cloudy and Breezy";
+        $retVal['skc']="Fair | Clear | Fair with Haze | Clear with Haze | Fair and Breezy | Clear and Breezy";
+        $retVal['few']="A Few Clouds | A Few Clouds with Haze | A Few Clouds and Breezy";
+        $retVal['sct']="Partly Cloudy | Party Cloudy with Haze | Partly Cloudy and Breezy";
+        $retVal['ovc']="Overcast | Overcast with Haze | Overcast and Breezy";
+        $retVal['nfg']="Fog/Mist | Fog | Freezing Fog | Shallow Fog | Partial Fog | Patches of Fog | Fog in Vicinity | Freezing Fog in Vicinity | Shallow Fog in Vicinity | Partial Fog in Vicinity | Patches of Fog in Vicinity | Showers in Vicinity Fog | Light Freezing Fog | Heavy Freezing Fog";
+        $retVal['smoke']="Smoke";
+        $retVal['fzra']="Freezing Rain | Freezing Drizzle | Light Freezing Rain | Light Freezing Drizzle | Heavy Freezing Rain | Heavy Freezing Drizzle | Freezing Rain in Vicinity | Freezing Drizzle in Vicinity";
+        $retVal['ip']="Ice Pellets | Light Ice Pellets | Heavy Ice Pellets | Ice Pellets in Vicinity | Showers Ice Pellets | Thunderstorm Ice Pellets | Ice Crystals | Hail | Small Hail/Snow Pellets | Light Small Hail/Snow Pellets | Heavy Small Hail/Snow Pellets | Showers Hail | Hail Showers";
+        $retVal['mix']="Freezing Rain Snow | Light Freezing Rain Snow | Heavy Freezing Rain Snow | Freezing Drizzle Snow | Light Freezing Drizzle Snow | Heavy Freezing Drizzle Snow | Snow Freezing Rain| Light Snow Freezing Rain | Heavy Snow Freezing Rain | Snow Freezing Drizzle | Light Snow Freezing Drizzle | Heavy Snow Freezing Drizzle";
+        $retVal['raip']="Rain Ice Pellets | Light Rain Ice Pellets | Heavy Rain Ice Pellets | Drizzle Ice Pellets | Light Drizzle Ice Pellets | Heavy Drizzle Ice Pellets | Ice Pellets Rain | Light Ice Pellets Rain | Heavy Ice Pellets Rain | Ice Pellets Drizzle | Light Ice Pellets Drizzle | Heavy Ice Pellets Drizzle";
+        $retVal['rasn']="Rain Snow | Light Rain Snow | Heavy Rain Snow | Snow Rain | Light Snow Rain | Heavy Snow Rain | Drizzle Snow | Light Drizzle Snow | Heavy Drizzle Snow | Snow Drizzle | Light Snow Drizzle | Heavy Snow Drizzle";
+        $retVal['shra']="Rain Showers | Light Rain Showers | Heavy Rain Showers | Rain Showers in Vicinity | Light Showers Rain | Heavy Showers Rain | Showers Rain | Showers Rain in Vicinity | Rain Showers Fog/Mist | Light Rain Showers Fog/Mist | Heavy Rain Showers Fog/Mist | Rain Showers in Vicinity Fog/Mist | Light Showers Rain Fog/Mist | Heavy Showers Rain Fog/Mist | Showers Rain Fog/Mist | Showers Rain in Vicinity Fog/Mist";
+        $retVal['tsra']="Thunderstorm | Light Thunderstorm Rain | Heavy Thunderstorm Rain | Thunderstorm Rain Fog/Mist | Light Thunderstorm Rain Fog/Mist | Heavy Thunderstorm Rain Fog/Mist | Thunderstorm Showers in Vicinity | | Light Thunderstorm Rain Haze | Heavy Thunderstorm Rain Haze | Thunderstorm Fog | Light Thunderstorm Rain Fog | Heavy Thunderstorm Rain Fog | Thunderstorm Light Rain | Thunderstorm Heavy Rain | Thunderstorm Rain Fog/Mist | Thunderstorm Light Rain Fog/Mist | Thunderstorm Heavy Rain Fog/Mist | Thunderstorm in Vicinity Fog/Mist | Thunderstorm Showers in Vicinity | Thunderstorm in Vicinity | Thunderstorm in Vicinity Haze | Thunderstorm Haze in Vicinity | Thunderstorm Light Rain Haze | Thunderstorm Heavy Rain Haze | Thunderstorm Fog | Thunderstorm Light Rain Fog | Thunderstorm Heavy Rain Fog | Thunderstorm Hail | Light Thunderstorm Rain Hail | Heavy Thunderstorm Rain Hail | Thunderstorm Rain Hail Fog/Mist | Light Thunderstorm Rain Hail Fog/Mist | Heavy Thunderstorm Rain Hail Fog/Mist | Thunderstorm Showers in Vicinity Hail | | Light Thunderstorm Rain Hail Haze | Heavy Thunderstorm Rain Hail Haze | Thunderstorm Hail Fog | Light Thunderstorm Rain Hail Fog | Heavy Thunderstorm Rain Hail Fog | Thunderstorm Light Rain Hail | Thunderstorm Heavy Rain Hail | Thunderstorm Rain Hail Fog/Mist | Thunderstorm Light Rain Hail Fog/Mist | Thunderstorm Heavy Rain Hail Fog/Mist | Thunderstorm in Vicinity Hail Fog/Mist | Thunderstorm Showers in Vicinity Hail | Thunderstorm in Vicinity Hail | Thunderstorm in Vicinity Hail Haze | Thunderstorm Haze in Vicinity Hail | Thunderstorm Light Rain Hail Haze | Thunderstorm Heavy Rain Hail Haze | Thunderstorm Hail Fog | Thunderstorm Light Rain Hail Fog | Thunderstorm Heavy Rain Hail Fog | Thunderstorm Small Hail/Snow Pellets | Thunderstorm Rain Small Hail/Snow Pellets | Light Thunderstorm Rain Small Hail/Snow Pellets | Heavy Thunderstorm Rain Small Hail/Snow Pellets";
+        $retVal['sn']="Snow | Light Snow | Heavy Snow | Snow Showers | Light Snow Showers | Heavy Snow Showers | Showers Snow | Light Showers Snow | Heavy Showers Snow | Snow Fog/Mist | Light Snow Fog/Mist | Heavy Snow Fog/Mist | Snow Showers Fog/Mist | Light Snow Showers Fog/Mist | Heavy Snow Showers Fog/Mist | Showers Snow Fog/Mist | Light Showers Snow Fog/Mist | Heavy Showers Snow Fog/Mist | Snow Fog | Light Snow Fog | Heavy Snow Fog | Snow Showers Fog | Light Snow Showers Fog | Heavy Snow Showers Fog | Showers Snow Fog | Light Showers Snow Fog | Heavy Showers Snow Fog | Showers in Vicinity Snow | Snow Showers in Vicinity | Snow Showers in Vicinity Fog/Mist | Snow Showers in Vicinity Fog | Low Drifting Snow | Blowing Snow | Snow Low Drifting Snow | Snow Blowing Snow | Light Snow Low Drifting Snow | Light Snow Blowing Snow | Heavy Snow Low Drifting Snow | Heavy Snow Blowing Snow | Thunderstorm Snow | Light Thunderstorm Snow | Heavy Thunderstorm Snow | Snow Grains | Light Snow Grains | Heavy Snow Grains | Heavy Blowing Snow | Blowing Snow in Vicinity";
+        $retVal['wind']="Windy | Fair and Windy | A Few Clouds and Windy | Partly Cloudy and Windy | Mostly Cloudy and Windy | Overcast and Windy";
+        $retVal['hi_shwrs']="Showers in Vicinity | Showers in Vicinity Fog/Mist | Showers in Vicinity Fog | Showers in Vicinity Haze";
+        $retVal['fzrara']="Freezing Rain Rain | Light Freezing Rain Rain | Heavy Freezing Rain Rain | Rain Freezing Rain | Light Rain Freezing Rain | Heavy Rain Freezing Rain | Freezing Drizzle Rain | Light Freezing Drizzle Rain | Heavy Freezing Drizzle Rain | Rain Freezing Drizzle | Light Rain Freezing Drizzle | Heavy Rain Freezing Drizzle";
+        $retVal['hi_tsra']="Thunderstorm in Vicinity | Thunderstorm in Vicinity Fog/Mist | Thunderstorm in Vicinity Fog | Thunderstorm Haze in Vicinity | Thunderstorm in Vicinity Haze";
+        $retVal['ra1']="Light Rain | Drizzle | Light Drizzle | Heavy Drizzle | Light Rain Fog/Mist | Drizzle Fog/Mist | Light Drizzle Fog/Mist | Heavy Drizzle Fog/Mist | Light Rain Fog | Drizzle Fog | Light Drizzle Fog | Heavy Drizzle Fog";
+        $retVal['ra']="Rain | Heavy Rain | Rain Fog/Mist | Heavy Rain Fog/Mist | Rain Fog | Heavy Rain Fog";
+        $retVal['nsvrtsra']="Funnel Cloud | Funnel Cloud in Vicinity | Tornado/Water Spout";
+        $retVal['dust']="Dust | Low Drifting Dust | Blowing Dust | Sand | Blowing Sand | Low Drifting Sand | Dust/Sand Whirls | Dust/Sand Whirls in Vicinity | Dust Storm | Heavy Dust Storm | Dust Storm in Vicinity | Sand Storm | Heavy Sand Storm | Sand Storm in Vicinity";
+        $retVal['mist']="Haze";
+        return $retVal;
+    }
+// end CLASS
+}
+?>
diff --git a/curweather/test.php b/curweather/test.php
new file mode 100644 (file)
index 0000000..cd51c23
--- /dev/null
@@ -0,0 +1,5 @@
+ <?php \r
+require_once  'getweather.php';\r
+$rpt = "KHVN";\r
+$wxdata = GetWeather::get($rpt);\r
+var_dump($rpt, $wxdata);
\ No newline at end of file
diff --git a/dav.tgz b/dav.tgz
new file mode 100644 (file)
index 0000000..a687dea
Binary files /dev/null and b/dav.tgz differ
index be81317741b2c89ac0b583107be2ba43940c7aa2..0f2b95d0ec1750d7d354ec0839b8ef61e3169489 100644 (file)
Binary files a/editplain.tgz and b/editplain.tgz differ
index 7d91c29526bfe498096638725107ed0598e7da38..966e2d8fde5eaebe3f6e19a788ae316d9f3532e4 100755 (executable)
@@ -1,7 +1,7 @@
 <?php
 /**
  * Name: Editplain
- * Description: Disable richtext (TinyMCE) editor for status posting
+ * Description: This addon is deprecated and has been replaced with the "Advanced Features" setting.  Admins should remove this addon when their core code is updated to include advanced feature settings.
  * Version: 1.0
  * Author: Mike Macgirvin <http://macgirvin.com/profile/mike>
  * 
index 0e5b28929a2942f5105b87922f563f5184f6fdeb..dabe1d09db19ebba110adfad1ae1ed77caf438bc 100755 (executable)
Binary files a/extcron.tgz and b/extcron.tgz differ
index e3c21209b3c33e28d8e34caef0181d98efd183f5..3eb34cdcb2dcd2e072d5c75dd5794a8d467c6dbc 100755 (executable)
@@ -5,7 +5,7 @@
  * Name: external cron
  * Description: Use external server or service to run poller regularly
  * Version: 1.0
- * Author: Mike Macgirvin <http://macgirvin.com/profile/mike>
+ * Author: Mike Macgirvin <https://macgirvin.com/profile/mike>
  * 
  * Notes: External service needs to make a web request to http(s)://yoursite/extcron
  */
index ff920dc60c6a7e0280d0b6972a2d94ce1abd2c88..2dbd4efd0f28329b0616821454299916880db917 100644 (file)
Binary files a/facebook.tgz and b/facebook.tgz differ
index 6786febbb553e876f155a7020b90999f66960fb5..4c1c0a14142dcc34e5768ceb103454fc0d5f2f2c 100644 (file)
@@ -383,10 +383,12 @@ function fb_get_friends_sync_full($uid, $access_token, $persons) {
         if($s) {
             $results = json_decode($s);
             logger('fb_get_friends: info: ' . print_r($results,true), LOGGER_DATA);
-            foreach ($results as $contact) {
-                if ($contact->code != 200) logger('fb_get_friends: not found: ' . print_r($contact,true), LOGGER_DEBUG);
-                else fb_get_friends_sync_parsecontact($uid, json_decode($contact->body));
-            }
+                       if(count($results)) {
+                   foreach ($results as $contact) {
+                   if ($contact->code != 200) logger('fb_get_friends: not found: ' . print_r($contact,true), LOGGER_DEBUG);
+                       else fb_get_friends_sync_parsecontact($uid, json_decode($contact->body));
+               }
+                       }
         }
     }
 }
@@ -1242,8 +1244,12 @@ function facebook_post_local(&$a,&$b) {
                $fb_enable = (($fb_post && x($_REQUEST,'facebook_enable')) ? intval($_REQUEST['facebook_enable']) : 0);
 
                // if API is used, default to the chosen settings
-               if($_REQUEST['api_source'] && intval(get_pconfig(local_user(),'facebook','post_by_default')))
-                       $fb_enable = 1;
+               // but allow a specific override
+
+               if($_REQUEST['api_source'] && intval(get_pconfig(local_user(),'facebook','post_by_default'))) {
+                       if(! x($_REQUEST,'facebook_enable'))
+                               $fb_enable = 1;
+               }
 
                if(! $fb_enable)
                        return;
diff --git a/fbpost.tgz b/fbpost.tgz
new file mode 100644 (file)
index 0000000..b118c6d
Binary files /dev/null and b/fbpost.tgz differ
diff --git a/fbpost/README.md b/fbpost/README.md
new file mode 100644 (file)
index 0000000..c214360
--- /dev/null
@@ -0,0 +1,18 @@
+Installing the Friendica/Facebook connector
+
+Detailed instructions how to use this plugin can be found at
+the [How to: Friendica's Facebook Connector](https://github.com/friendica/friendica/wiki/How-to:-Friendica%E2%80%99s-Facebook-connector) page.
+
+Vidoes and embeds will not be posted if there is no other content. Links 
+and images will be converted to a format suitable for the Facebook API and 
+long posts truncated - with a link to view the full post. 
+
+Facebook contacts will not be able to view private photos, as they are not able to
+authenticate to your site to establish identity. We will address this 
+in a future release.
+
+This addon will only post your entries to your Facebook account but won't fetch
+content from there.
+
+Info: please make sure that you understand all aspects due to Friendica's 
+default licence which is: [MIT License](https://github.com/friendica/friendica/blob/master/LICENSE)
diff --git a/fbpost/fbpost.css b/fbpost/fbpost.css
new file mode 100644 (file)
index 0000000..224d27b
--- /dev/null
@@ -0,0 +1,13 @@
+
+#fbpost-enable-wrapper {
+       margin-top: 20px;
+}
+
+#fbpost-disable-wrapper {
+       margin-top: 20px;
+}
+
+#fbpost-post-default-form input {
+       margin-top: 20px;
+       margin-right: 20px;
+}
\ No newline at end of file
diff --git a/fbpost/fbpost.php b/fbpost/fbpost.php
new file mode 100644 (file)
index 0000000..ba60f4e
--- /dev/null
@@ -0,0 +1,1201 @@
+<?php
+/**
+ * Name: Facebook Post Connector
+ * Version: 1.3
+ * Author: Mike Macgirvin <http://macgirvin.com/profile/mike>
+ * Author: Tobias Hößl <https://github.com/CatoTH/>
+ *
+ */
+
+/**
+ * Installing the Friendica/Facebook connector
+ *
+ * Detailed instructions how to use this plugin can be found at
+ * https://github.com/friendica/friendica/wiki/How-to:-Friendica%E2%80%99s-Facebook-connector
+ *
+ * Vidoes and embeds will not be posted if there is no other content. Links 
+ * and images will be converted to a format suitable for the Facebook API and 
+ * long posts truncated - with a link to view the full post. 
+ *
+ * Facebook contacts will not be able to view private photos, as they are not able to
+ * authenticate to your site to establish identity. We will address this 
+ * in a future release.
+ */
+
+define('FACEBOOK_DEFAULT_POLL_INTERVAL', 5); // given in minutes
+
+require_once('include/security.php');
+
+function fbpost_install() {
+       register_hook('post_local',       'addon/fbpost/fbpost.php', 'fbpost_post_local');
+       register_hook('notifier_normal',  'addon/fbpost/fbpost.php', 'fbpost_post_hook');
+       register_hook('jot_networks',     'addon/fbpost/fbpost.php', 'fbpost_jot_nets');
+       register_hook('connector_settings',  'addon/fbpost/fbpost.php', 'fbpost_plugin_settings');
+       register_hook('enotify',          'addon/fbpost/fbpost.php', 'fbpost_enotify');
+       register_hook('queue_predeliver', 'addon/fbpost/fbpost.php', 'fbpost_queue_hook');
+       register_hook('cron',             'addon/fbpost/fbpost.php', 'fbpost_cron');
+}
+
+
+function fbpost_uninstall() {
+       unregister_hook('post_local',       'addon/fbpost/fbpost.php', 'fbpost_post_local');
+       unregister_hook('notifier_normal',  'addon/fbpost/fbpost.php', 'fbpost_post_hook');
+       unregister_hook('jot_networks',     'addon/fbpost/fbpost.php', 'fbpost_jot_nets');
+       unregister_hook('connector_settings',  'addon/fbpost/fbpost.php', 'fbpost_plugin_settings');
+       unregister_hook('enotify',          'addon/fbpost/fbpost.php', 'fbpost_enotify');
+       unregister_hook('queue_predeliver', 'addon/fbpost/fbpost.php', 'fbpost_queue_hook');
+       unregister_hook('cron',             'addon/fbpost/fbpost.php', 'fbpost_cron');
+}
+
+
+/* declare the fbpost_module function so that /fbpost url requests will land here */
+
+function fbpost_module() {}
+
+
+
+// If a->argv[1] is a nickname, this is a callback from Facebook oauth requests.
+// If $_REQUEST["realtime_cb"] is set, this is a callback from the Real-Time Updates API
+
+/**
+ * @param App $a
+ */
+function fbpost_init(&$a) {
+
+       if($a->argc != 2)
+               return;
+
+       $nick = $a->argv[1];
+
+       if(strlen($nick))
+               $r = q("SELECT `uid` FROM `user` WHERE `nickname` = '%s' LIMIT 1",
+                               dbesc($nick)
+               );
+       if(!(isset($r) && count($r)))
+               return;
+
+       $uid           = $r[0]['uid'];
+       $auth_code     = (x($_GET, 'code') ? $_GET['code'] : '');
+       $error         = (x($_GET, 'error_description') ? $_GET['error_description'] : '');
+
+
+       if($error)
+               logger('fbpost_init: Error: ' . $error);
+
+       if($auth_code && $uid) {
+
+               $appid = get_config('facebook','appid');
+               $appsecret = get_config('facebook', 'appsecret');
+
+               $x = fetch_url('https://graph.facebook.com/oauth/access_token?client_id='
+                       . $appid . '&client_secret=' . $appsecret . '&redirect_uri='
+                       . urlencode($a->get_baseurl() . '/fbpost/' . $nick)
+                       . '&code=' . $auth_code);
+
+               logger('fbpost_init: returned access token: ' . $x, LOGGER_DATA);
+
+               if(strpos($x,'access_token=') !== false) {
+                       $token = str_replace('access_token=', '', $x);
+                       if(strpos($token,'&') !== false)
+                               $token = substr($token,0,strpos($token,'&'));
+                       set_pconfig($uid,'facebook','access_token',$token);
+                       set_pconfig($uid,'facebook','post','1');
+                       fbpost_get_self($uid);
+               }
+
+       }
+
+}
+
+
+/**
+ * @param int $uid
+ */
+function fbpost_get_self($uid) {
+       $access_token = get_pconfig($uid,'facebook','access_token');
+       if(! $access_token)
+               return;
+       $s = fetch_url('https://graph.facebook.com/me/?access_token=' . $access_token);
+       if($s) {
+               $j = json_decode($s);
+               set_pconfig($uid,'facebook','self_id',(string) $j->id);
+       }
+}
+
+
+// This is the POST method to the facebook settings page
+// Content is posted to Facebook in the function facebook_post_hook()
+
+/**
+ * @param App $a
+ */
+function fbpost_post(&$a) {
+
+       $uid = local_user();
+       if($uid){
+
+
+               $fb_limited = get_config('facebook','crestrict');
+
+
+               $value = ((x($_POST,'post_by_default')) ? intval($_POST['post_by_default']) : 0);
+               set_pconfig($uid,'facebook','post_by_default', $value);
+
+               $value = ((x($_POST,'mirror_posts')) ? intval($_POST['mirror_posts']) : 0);
+               set_pconfig($uid,'facebook','mirror_posts', $value);
+
+               $value = ((x($_POST,'suppress_view_on_friendica')) ? intval($_POST['suppress_view_on_friendica']) : 0);
+               set_pconfig($uid,'facebook','suppress_view_on_friendica', $value);
+
+               $value = ((x($_POST,'post_to_page')) ? $_POST['post_to_page'] : "0-0");
+               $values = explode("-", $value);
+               set_pconfig($uid,'facebook','post_to_page', $values[0]);
+               set_pconfig($uid,'facebook','page_access_token', $values[1]);
+
+               info( t('Settings updated.') . EOL);
+       }
+
+       return;
+}
+
+// Facebook settings form
+
+/**
+ * @param App $a
+ * @return string
+ */
+function fbpost_content(&$a) {
+
+       if(! local_user()) {
+               notice( t('Permission denied.') . EOL);
+               return '';
+       }
+
+
+       if(! service_class_allows(local_user(),'facebook_connect')) {
+               notice( t('Permission denied.') . EOL);
+               return upgrade_bool_message();
+       }
+
+
+       if($a->argc > 1 && $a->argv[1] === 'remove') {
+               del_pconfig(local_user(),'facebook','post');
+               info( t('Facebook Post disabled') . EOL);
+       }
+
+       $o = '';
+       
+       $fb_installed = false;
+       if (get_pconfig(local_user(),'facebook','post')) {
+               $access_token = get_pconfig(local_user(),'facebook','access_token');
+               if ($access_token) {
+                       $s = fetch_url('https://graph.facebook.com/me/feed?access_token=' . $access_token);
+                       if($s) {
+                               $j = json_decode($s);
+                               if (isset($j->data)) $fb_installed = true;
+                       }
+               }
+       }
+       
+       $appid = get_config('facebook','appid');
+
+       if(! $appid) {
+               notice( t('Facebook API key is missing.') . EOL);
+               return '';
+       }
+
+       $a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="'
+               . $a->get_baseurl() . '/addon/fbpost/fbpost.css' . '" media="all" />' . "\r\n";
+
+       $o .= '<h3>' . t('Facebook Post') . '</h3>';
+
+       if(! $fb_installed) { 
+               $o .= '<div id="fbpost-enable-wrapper">';
+
+               $o .= '<a href="https://www.facebook.com/dialog/oauth?client_id=' . $appid . '&redirect_uri=' 
+                       . $a->get_baseurl() . '/fbpost/' . $a->user['nickname'] . '&scope=read_stream,publish_stream,manage_pages,photo_upload,user_groups,offline_access">' . t('Install Facebook Post connector for this account.') . '</a>';
+               $o .= '</div>';
+       }
+
+       if($fb_installed) {
+               $o .= '<div id="fbpost-disable-wrapper">';
+
+               $o .= '<a href="' . $a->get_baseurl() . '/fbpost/remove' . '">' . t('Remove Facebook Post connector') . '</a></div>';
+
+               $o .= '<div id="fbpost-enable-wrapper">';
+
+               $o .= '<a href="https://www.facebook.com/dialog/oauth?client_id=' . $appid . '&redirect_uri=' 
+                       . $a->get_baseurl() . '/fbpost/' . $a->user['nickname'] . '&scope=read_stream,publish_stream,manage_pages,photo_upload,user_groups,offline_access">' . t('Re-authenticate [This is necessary whenever your Facebook password is changed.]') . '</a>';
+               $o .= '</div>';
+
+               $o .= '<div id="fbpost-post-default-form">';
+               $o .= '<form action="fbpost" method="post" >';
+               $post_by_default = get_pconfig(local_user(),'facebook','post_by_default');
+               $checked = (($post_by_default) ? ' checked="checked" ' : '');
+               $o .= '<input type="checkbox" name="post_by_default" value="1"' . $checked . '/>' . ' ' . t('Post to Facebook by default') . EOL;
+
+               $suppress_view_on_friendica = get_pconfig(local_user(),'facebook','suppress_view_on_friendica');
+               $checked = (($suppress_view_on_friendica) ? ' checked="checked" ' : '');
+               $o .= '<input type="checkbox" name="suppress_view_on_friendica" value="1"' . $checked . '/>' . ' ' . t('Suppress "View on friendica"') . EOL;
+
+               $mirror_posts = get_pconfig(local_user(),'facebook','mirror_posts');
+               $checked = (($mirror_posts) ? ' checked="checked" ' : '');
+               $o .= '<input type="checkbox" name="mirror_posts" value="1"' . $checked . '/>' . ' ' . t('Mirror wall posts from facebook to friendica.') . EOL;
+
+               // List all pages
+               $post_to_page = get_pconfig(local_user(),'facebook','post_to_page');
+               $page_access_token = get_pconfig(local_user(),'facebook','page_access_token');
+               $fb_token  = get_pconfig($a->user['uid'],'facebook','access_token');
+               $url = 'https://graph.facebook.com/me/accounts';
+               $x = fetch_url($url."?access_token=".$fb_token);
+               $accounts = json_decode($x);
+
+               $o .= t("Post to page/group:")."<select name='post_to_page'>";
+               if (intval($post_to_page) == 0)
+                       $o .= "<option value='0-0' selected>".t('None')."</option>";
+               else
+                       $o .= "<option value='0-0'>".t('None')."</option>";
+
+               foreach($accounts->data as $account) {
+                       if (is_array($account->perms))
+                               if ($post_to_page == $account->id)
+                                       $o .= "<option value='".$account->id."-".$account->access_token."' selected>".$account->name."</option>";
+                               else
+                                       $o .= "<option value='".$account->id."-".$account->access_token."'>".$account->name."</option>";
+               }
+
+               $url = 'https://graph.facebook.com/me/groups';
+               $x = fetch_url($url."?access_token=".$fb_token);
+               $groups = json_decode($x);
+
+               foreach($groups->data as $group) {
+                       if ($post_to_page == $group->id)
+                               $o .= "<option value='".$group->id."-0' selected>".$group->name."</option>";
+                       else
+                               $o .= "<option value='".$group->id."-0'>".$group->name."</option>";
+               }
+
+               $o .= "</select>";
+
+               $o .= '<p><input type="submit" name="submit" value="' . t('Submit') . '" /></form></div>';
+
+       }
+
+       return $o;
+}
+
+/**
+ * @param App $a
+ * @param null|object $b
+ */
+function fbpost_plugin_settings(&$a,&$b) {
+
+       $b .= '<div class="settings-block">';
+       $b .= '<h3>' . t('Facebook') . '</h3>';
+       $b .= '<a href="fbpost">' . t('Facebook Post Settings') . '</a><br />';
+       $b .= '</div>';
+
+}
+
+
+/**
+ * @param App $a
+ * @param null|object $o
+ */
+function fbpost_plugin_admin(&$a, &$o){
+
+
+       $o = '<input type="hidden" name="form_security_token" value="' . get_form_security_token("fbsave") . '">';
+       
+       $o .= '<h4>' . t('Facebook API Key') . '</h4>';
+       
+       $appid  = get_config('facebook', 'appid'  );
+       $appsecret = get_config('facebook', 'appsecret' );
+       
+       $ret1 = q("SELECT `v` FROM `config` WHERE `cat` = 'facebook' AND `k` = 'appid' LIMIT 1");
+       $ret2 = q("SELECT `v` FROM `config` WHERE `cat` = 'facebook' AND `k` = 'appsecret' LIMIT 1");
+       if ((count($ret1) > 0 && $ret1[0]['v'] != $appid) || (count($ret2) > 0 && $ret2[0]['v'] != $appsecret)) $o .= t('Error: it appears that you have specified the App-ID and -Secret in your .htconfig.php file. As long as they are specified there, they cannot be set using this form.<br><br>');
+       
+       $o .= '<label for="fb_appid">' . t('App-ID / API-Key') . '</label><input id="fb_appid" name="appid" type="text" value="' . escape_tags($appid ? $appid : "") . '"><br style="clear: both;">';
+       $o .= '<label for="fb_appsecret">' . t('Application secret') . '</label><input id="fb_appsecret" name="appsecret" type="text" value="' . escape_tags($appsecret ? $appsecret : "") . '"><br style="clear: both;">';
+
+       $o .= '<input type="submit" name="fb_save_keys" value="' . t('Save') . '">';
+       
+}
+
+/**
+ * @param App $a
+ */
+
+function fbpost_plugin_admin_post(&$a){
+       check_form_security_token_redirectOnErr('/admin/plugins/fbpost', 'fbsave');
+       
+       if (x($_REQUEST,'fb_save_keys')) {
+               set_config('facebook', 'appid', $_REQUEST['appid']);
+               set_config('facebook', 'appsecret', $_REQUEST['appsecret']);
+
+               info(t('The new values have been saved.'));
+       }
+
+}
+
+/**
+ * @param App $a
+ * @param object $b
+ * @return mixed
+ */
+function fbpost_jot_nets(&$a,&$b) {
+       if(! local_user())
+               return;
+
+       $fb_post = get_pconfig(local_user(),'facebook','post');
+       if(intval($fb_post) == 1) {
+               $fb_defpost = get_pconfig(local_user(),'facebook','post_by_default');
+               $selected = ((intval($fb_defpost) == 1) ? ' checked="checked" ' : '');
+               $b .= '<div class="profile-jot-net"><input type="checkbox" name="facebook_enable"' . $selected . ' value="1" /> ' 
+                       . t('Post to Facebook') . '</div>';
+       }
+}
+
+function fbpost_ShareAttributes($match) {
+
+        $attributes = $match[1];
+
+        $author = "";
+        preg_match("/author='(.*?)'/ism", $attributes, $matches);
+        if ($matches[1] != "")
+                $author = $matches[1];
+
+        preg_match('/author="(.*?)"/ism', $attributes, $matches);
+        if ($matches[1] != "")
+                $author = $matches[1];
+
+        $headline = '<div class="shared_header">';
+
+        $headline .= sprintf(t('%s:'), $author);
+
+        $headline .= "</div>";
+
+       //$text = "<br />".$headline."</strong><blockquote>".$match[2]."</blockquote>";
+       $text = "\n\t".$match[2].":\t";
+
+        return($text);
+}
+
+
+/**
+ * @param App $a
+ * @param object $b
+ * @return mixed
+ */
+function fbpost_post_hook(&$a,&$b) {
+
+
+       if($b['deleted'] || ($b['created'] !== $b['edited']))
+               return;
+
+       // Don't transmit answers (have to be cleaned up in the following code)
+       if($b['parent'] != $b['id'])
+               return;
+
+       // if post comes from facebook don't send it back
+       if($b['app'] == "Facebook")
+               return;
+
+       /**
+        * Post to Facebook stream
+        */
+
+       require_once('include/group.php');
+       require_once('include/html2plain.php');
+
+       logger('Facebook post');
+
+       $reply = false;
+       $likes = false;
+
+       $deny_arr = array();
+       $allow_arr = array();
+
+       $toplevel = (($b['id'] == $b['parent']) ? true : false);
+
+
+       $linking = ((get_pconfig($b['uid'],'facebook','no_linking')) ? 0 : 1);
+
+       if((! $toplevel) && ($linking)) {
+               $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1",
+                       intval($b['parent']),
+                       intval($b['uid'])
+               );
+               if(count($r) && substr($r[0]['uri'],0,4) === 'fb::')
+                       $reply = substr($r[0]['uri'],4);
+               elseif(count($r) && substr($r[0]['extid'],0,4) === 'fb::')
+                       $reply = substr($r[0]['extid'],4);
+               else
+                       return;
+
+               $u = q("SELECT * FROM user where uid = %d limit 1",
+                       intval($b['uid'])
+               );
+               if(! count($u))
+                       return;
+
+               // only accept comments from the item owner. Other contacts are unknown to FB.
+
+               if(! link_compare($b['author-link'], $a->get_baseurl() . '/profile/' . $u[0]['nickname']))
+                       return;
+
+
+               logger('facebook reply id=' . $reply);
+       }
+
+       if(strstr($b['postopts'],'facebook') || ($b['private']) || ($reply)) {
+
+               if($b['private'] && $reply === false) {
+                       $allow_people = expand_acl($b['allow_cid']);
+                       $allow_groups = expand_groups(expand_acl($b['allow_gid']));
+                       $deny_people  = expand_acl($b['deny_cid']);
+                       $deny_groups  = expand_groups(expand_acl($b['deny_gid']));
+
+                       $recipients = array_unique(array_merge($allow_people,$allow_groups));
+                       $deny = array_unique(array_merge($deny_people,$deny_groups));
+
+                       $allow_str = dbesc(implode(', ',$recipients));
+                       if($allow_str) {
+                               $r = q("SELECT `notify` FROM `contact` WHERE `id` IN ( $allow_str ) AND `network` = 'face'"); 
+                               if(count($r))
+                                       foreach($r as $rr)
+                                               $allow_arr[] = $rr['notify'];
+                       }
+
+                       $deny_str = dbesc(implode(', ',$deny));
+                       if($deny_str) {
+                               $r = q("SELECT `notify` FROM `contact` WHERE `id` IN ( $deny_str ) AND `network` = 'face'"); 
+                               if(count($r))
+                                       foreach($r as $rr)
+                                               $deny_arr[] = $rr['notify'];
+                       }
+
+                       if(count($deny_arr) && (! count($allow_arr))) {
+
+                               // One or more FB folks were denied access but nobody on FB was specifically allowed access.
+                               // This might cause the post to be open to public on Facebook, but only to selected members
+                               // on another network. Since this could potentially leak a post to somebody who was denied, 
+                               // we will skip posting it to Facebook with a slightly vague but relevant message that will 
+                               // hopefully lead somebody to this code comment for a better explanation of what went wrong.
+
+                               notice( t('Post to Facebook cancelled because of multi-network access permission conflict.') . EOL);
+                               return;
+                       }
+
+
+                       // if it's a private message but no Facebook members are allowed or denied, skip Facebook post
+
+                       if((! count($allow_arr)) && (! count($deny_arr)))
+                               return;
+               }
+
+               if($b['verb'] == ACTIVITY_LIKE)
+                       $likes = true;
+
+
+               $appid  = get_config('facebook', 'appid'  );
+               $secret = get_config('facebook', 'appsecret' );
+
+               if($appid && $secret) {
+
+                       logger('facebook: have appid+secret');
+
+                       $fb_token  = get_pconfig($b['uid'],'facebook','access_token');
+
+
+                       // post to facebook if it's a public post and we've ticked the 'post to Facebook' box,
+                       // or it's a private message with facebook participants
+                       // or it's a reply or likes action to an existing facebook post
+
+                       if($fb_token && ($toplevel || $b['private'] || $reply)) {
+                               logger('facebook: able to post');
+                               require_once('library/facebook.php');
+                               require_once('include/bbcode.php');
+
+                               $msg = $b['body'];
+
+                               logger('Facebook post: original msg=' . $msg, LOGGER_DATA);
+
+                               // make links readable before we strip the code
+
+                               // unless it's a dislike - just send the text as a comment
+
+                               // if($b['verb'] == ACTIVITY_DISLIKE)
+                               //      $msg = trim(strip_tags(bbcode($msg)));
+
+                               // Old code
+                               /*$search_str = $a->get_baseurl() . '/search';
+
+                               if(preg_match("/\[url=(.*?)\](.*?)\[\/url\]/is",$msg,$matches)) {
+
+                                       // don't use hashtags for message link
+
+                                       if(strpos($matches[2],$search_str) === false) {
+                                               $link = $matches[1];
+                                               if(substr($matches[2],0,5) != '[img]')
+                                                       $linkname = $matches[2];
+                                       }
+                               }
+
+                               // strip tag links to avoid link clutter, this really should be 
+                               // configurable because we're losing information
+
+                               $msg = preg_replace("/\#\[url=(.*?)\](.*?)\[\/url\]/is",'#$2',$msg);
+
+                               // provide the link separately for normal links
+                               $msg = preg_replace("/\[url=(.*?)\](.*?)\[\/url\]/is",'$2 $1',$msg);
+
+                               if(preg_match("/\[img\](.*?)\[\/img\]/is",$msg,$matches))
+                                       $image = $matches[1];
+
+                               $msg = preg_replace("/\[img\](.*?)\[\/img\]/is", t('Image: ') . '$1', $msg);
+
+                               if((strpos($link,z_root()) !== false) && (! $image))
+                                       $image = $a->get_baseurl() . '/images/friendica-64.jpg';
+
+                               $msg = trim(strip_tags(bbcode($msg)));*/
+
+                               // New code
+
+                               // Looking for the first image
+                               $image = '';
+                               if(preg_match("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/is",$b['body'],$matches))
+                                       $image = $matches[3];
+
+                               if ($image == '')
+                                       if(preg_match("/\[img\](.*?)\[\/img\]/is",$b['body'],$matches))
+                                               $image = $matches[1];
+
+                               // When saved into the database the content is sent through htmlspecialchars
+                               // That means that we have to decode all image-urls
+                               $image = htmlspecialchars_decode($image);
+
+                               // Checking for a bookmark element
+                               $body = $b['body'];
+                               if (strpos($body, "[bookmark") !== false) {
+                                       // splitting the text in two parts:
+                                       // before and after the bookmark
+                                       $pos = strpos($body, "[bookmark");
+                                       $body1 = substr($body, 0, $pos);
+                                       $body2 = substr($body, $pos);
+
+                                       // Removing the bookmark and all quotes after the bookmark
+                                       // they are mostly only the content after the bookmark.
+                                       $body2 = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",'',$body2);
+                                       $body2 = preg_replace("/\[quote\=([^\]]*)\](.*?)\[\/quote\]/ism",'',$body2);
+                                       $body2 = preg_replace("/\[quote\](.*?)\[\/quote\]/ism",'',$body2);
+
+                                       $body = $body1.$body2;
+                               }
+
+                               // Convert recycle signs
+                               $body = str_replace("\t", " ", $body);
+                               // recycle 1
+                               $recycle = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8');
+                               $body = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', "\n\t$2:\t", $body);
+                               // recycle 2 (Test)
+                               $recycle = html_entity_decode("&#x25CC; ", ENT_QUOTES, 'UTF-8');
+                               $body = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', "\n\t$2:\t", $body);
+
+                               // share element
+                               $body = preg_replace_callback("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]/ism","fbpost_ShareAttributes", $body);
+
+                               $bodyparts = explode("\t", $body);
+                               // Doesn't help with multiple repeats - the problem has to be solved later
+                               if (sizeof($bodyparts) == 3) {
+                                       $html = bbcode($bodyparts[2], false, false);
+                                       $test = trim(html2plain($html, 0, true));
+
+                                       if (trim($bodyparts[0]) == "")
+                                               $body = trim($bodyparts[2]);
+                                       else if (trim($test) == "")
+                                               $body = trim($bodyparts[0]);
+                                       else
+                                               $body = trim($bodyparts[0])."\n\n".trim($bodyparts[1])."[quote]".trim($bodyparts[2])."[/quote]";
+                               } else
+                                       $body = str_replace("\t", "", $body);
+
+                               // At first convert the text to html
+                               $html = bbcode($body, false, false);
+
+                               // Then convert it to plain text
+                               $msg = trim($b['title']." \n\n".html2plain($html, 0, true));
+
+                               // Removing useless spaces
+                               if (substr($msg, -2) == "«")
+                                       $msg = trim(substr($msg, 0, -2))."«";
+
+                               $msg = html_entity_decode($msg,ENT_QUOTES,'UTF-8');
+
+                               // Removing multiple newlines
+                               while (strpos($msg, "\n\n\n") !== false)
+                                       $msg = str_replace("\n\n\n", "\n\n", $msg);
+
+                               // add any attachments as text urls
+                               $arr = explode(',',$b['attach']);
+
+                               if(count($arr)) {
+                                       $msg .= "\n";
+                                       foreach($arr as $r) {
+                                               $matches = false;
+                                               $cnt = preg_match('|\[attach\]href=\"(.*?)\" size=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"\[\/attach\]|',$r,$matches);
+                                               if($cnt) {
+                                                       $msg .= "\n".$matches[1];
+                                               }
+                                       }
+                               }
+
+                               $link = '';
+                               $linkname = '';
+                               // look for bookmark-bbcode and handle it with priority
+                               if(preg_match("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/is",$b['body'],$matches)) {
+                                       $link = $matches[1];
+                                       $linkname = $matches[2];
+                               }
+
+                               // If there is no bookmark element then take the first link
+                               if ($link == '') {
+                                       $links = collecturls($html);
+                                       if (sizeof($links) > 0) {
+                                               reset($links);
+                                               $link = current($links);
+                                       }
+                               }
+
+                               // Remove trailing and leading spaces
+                               $msg = trim($msg);
+
+
+                               // Fallback - if message is empty
+                               if(!strlen($msg))
+                                       $msg = $linkname;
+
+                               if(!strlen($msg))
+                                       $msg = $link;
+
+                               if(!strlen($msg))
+                                       $msg = $image;
+
+                               // If there is nothing to post then exit
+                               if(!strlen($msg))
+                                       return;
+
+                               logger('Facebook post: msg=' . $msg, LOGGER_DATA);
+
+                               $video = "";
+
+                               if($likes) {
+                                       $postvars = array('access_token' => $fb_token);
+                               } else {
+                                       // message, picture, link, name, caption, description, source, place, tags
+                                       if(trim($link) != "")
+                                               if (@exif_imagetype($link) != 0) {
+                                                       $image = $link;
+                                                       $link = "";
+                                               }
+
+                                       $postvars = array(
+                                               'access_token' => $fb_token,
+                                               'message' => $msg
+                                       );
+                                       if(trim($image) != "")
+                                               $postvars['picture'] = $image;
+
+                                       if(trim($link) != "") {
+                                               $postvars['link'] = $link;
+
+                                               if ((stristr($link,'youtube')) || (stristr($link,'youtu.be')) || (stristr($link,'vimeo'))) {
+                                                       $video = $link;
+                                               }
+                                       }
+                                       if(trim($linkname) != "")
+                                               $postvars['name'] = $linkname;
+                               }
+
+                               if(($b['private']) && ($toplevel)) {
+                                       $postvars['privacy'] = '{"value": "CUSTOM", "friends": "SOME_FRIENDS"';
+                                       if(count($allow_arr))
+                                               $postvars['privacy'] .= ',"allow": "' . implode(',',$allow_arr) . '"';
+                                       if(count($deny_arr))
+                                               $postvars['privacy'] .= ',"deny": "' . implode(',',$deny_arr) . '"';
+                                       $postvars['privacy'] .= '}';
+
+                               }
+
+                               $post_to_page = get_pconfig($b['uid'],'facebook','post_to_page');
+                               $page_access_token = get_pconfig($b['uid'],'facebook','page_access_token');
+                               if ((intval($post_to_page) != 0) and ($page_access_token != ""))
+                                       $target = $post_to_page;
+                               else
+                                       $target = "me";
+
+                               if($reply) {
+                                       $url = 'https://graph.facebook.com/' . $reply . '/' . (($likes) ? 'likes' : 'comments');
+                               } else if (($video != "") or (($image == "") and ($link != ""))) {
+                                       // If it is a link to a video or a link without a preview picture then post it as a link
+                                       if ($video != "")
+                                               $link = $video;
+
+                                       $postvars = array(
+                                               'access_token' => $fb_token,
+                                               'link' => $link,
+                                       );
+                                       if ($msg != $video)
+                                               $postvars['message'] = $msg;
+
+                                       $url = 'https://graph.facebook.com/'.$target.'/links';
+                               } else if (($link == "") and ($image != "")) {
+                                       // If it is only an image without a page link then post this image as a photo
+                                       $postvars = array(
+                                               'access_token' => $fb_token,
+                                               'url' => $image,
+                                       );
+                                       if ($msg != $image)
+                                               $postvars['message'] = $msg;
+
+                                       $url = 'https://graph.facebook.com/'.$target.'/photos';
+                               } else if (($link != "") or ($image != "") or ($b['title'] == '') or (strlen($msg) < 500)) {
+                                       $url = 'https://graph.facebook.com/'.$target.'/feed';
+                                       if (!get_pconfig($b['uid'],'facebook','suppress_view_on_friendica') and $b['plink'])
+                                               $postvars['actions'] = '{"name": "' . t('View on Friendica') . '", "link": "' .  $b['plink'] . '"}';
+                               } else {
+                                       // if its only a message and a subject and the message is larger than 500 characters then post it as note
+                                       $postvars = array(
+                                               'access_token' => $fb_token,
+                                               'message' => bbcode($b['body'], false, false),
+                                               'subject' => $b['title'],
+                                       );
+                                       $url = 'https://graph.facebook.com/'.$target.'/notes';
+                               }
+
+                               // Post to page?
+                               if (!$reply and ($target != "me") and $page_access_token)
+                                       $postvars['access_token'] = $page_access_token;
+
+                               logger('facebook: post to ' . $url);
+                               logger('facebook: postvars: ' . print_r($postvars,true));
+
+                               // "test_mode" prevents anything from actually being posted.
+                               // Otherwise, let's do it.
+
+                               if(! get_config('facebook','test_mode')) {
+                                       $x = post_url($url, $postvars);
+                                       logger('Facebook post returns: ' . $x, LOGGER_DEBUG);
+
+                                       $retj = json_decode($x);
+                                       if($retj->id) {
+                                               q("UPDATE `item` SET `extid` = '%s' WHERE `id` = %d LIMIT 1",
+                                                       dbesc('fb::' . $retj->id),
+                                                       intval($b['id'])
+                                               );
+                                       }
+                                       else {
+                                               if(! $likes) {
+                                                       $s = serialize(array('url' => $url, 'item' => $b['id'], 'post' => $postvars));
+                                                       require_once('include/queue_fn.php');
+                                                       add_to_queue($a->contact,NETWORK_FACEBOOK,$s);
+                                                       notice( t('Facebook post failed. Queued for retry.') . EOL);
+                                               }
+
+                                               if (isset($retj->error) && $retj->error->type == "OAuthException" && $retj->error->code == 190) {
+                                                       logger('Facebook session has expired due to changed password.', LOGGER_DEBUG);
+
+                                                       $last_notification = get_pconfig($b['uid'], 'facebook', 'session_expired_mailsent');
+                                                       if (!$last_notification || $last_notification < (time() - FACEBOOK_SESSION_ERR_NOTIFICATION_INTERVAL)) {
+                                                               require_once('include/enotify.php');
+
+                                                               $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($b['uid']) );
+                                                               notification(array(
+                                                                       'uid' => $b['uid'],
+                                                                       'type' => NOTIFY_SYSTEM,
+                                                                       'system_type' => 'facebook_connection_invalid',
+                                                                       'language'     => $r[0]['language'],
+                                                                       'to_name'      => $r[0]['username'],
+                                                                       'to_email'     => $r[0]['email'],
+                                                                       'source_name'  => t('Administrator'),
+                                                                       'source_link'  => $a->config["system"]["url"],
+                                                                       'source_photo' => $a->config["system"]["url"] . '/images/person-80.jpg',
+                                                               ));
+
+                                                               set_pconfig($b['uid'], 'facebook', 'session_expired_mailsent', time());
+                                                       } else logger('Facebook: No notification, as the last one was sent on ' . $last_notification, LOGGER_DEBUG);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+/**
+ * @param App $app
+ * @param object $data
+ */
+function fbpost_enotify(&$app, &$data) {
+       if (x($data, 'params') && $data['params']['type'] == NOTIFY_SYSTEM && x($data['params'], 'system_type') && $data['params']['system_type'] == 'facebook_connection_invalid') {
+               $data['itemlink'] = '/facebook';
+               $data['epreamble'] = $data['preamble'] = t('Your Facebook connection became invalid. Please Re-authenticate.');
+               $data['subject'] = t('Facebook connection became invalid');
+               $data['body'] = sprintf( t("Hi %1\$s,\n\nThe connection between your accounts on %2\$s and Facebook became invalid. This usually happens after you change your Facebook-password. To enable the connection again, you have to %3\$sre-authenticate the Facebook-connector%4\$s."), $data['params']['to_name'], "[url=" . $app->config["system"]["url"] . "]" . $app->config["sitename"] . "[/url]", "[url=" . $app->config["system"]["url"] . "/facebook]", "[/url]");
+       }
+}
+
+/**
+ * @param App $a
+ * @param object $b
+ */
+function fbpost_post_local(&$a,&$b) {
+
+       // Figure out if Facebook posting is enabled for this post and file it in 'postopts'
+       // where we will discover it during background delivery.
+
+       // This can only be triggered by a local user posting to their own wall.
+
+       if((local_user()) && (local_user() == $b['uid'])) {
+
+               $fb_post   = intval(get_pconfig(local_user(),'facebook','post'));
+               $fb_enable = (($fb_post && x($_REQUEST,'facebook_enable')) ? intval($_REQUEST['facebook_enable']) : 0);
+
+               // if API is used, default to the chosen settings
+               // but allow a specific override
+
+               if($_REQUEST['api_source'] && intval(get_pconfig(local_user(),'facebook','post_by_default'))) {
+                       if(! x($_REQUEST,'facebook_enable'))
+                               $fb_enable = 1;
+               }
+
+               if(! $fb_enable)
+                       return;
+
+               if(strlen($b['postopts']))
+                       $b['postopts'] .= ',';
+               $b['postopts'] .= 'facebook';
+       }
+}
+
+
+/**
+ * @param App $a
+ * @param object $b
+ */
+function fbpost_queue_hook(&$a,&$b) {
+
+       $qi = q("SELECT * FROM `queue` WHERE `network` = '%s'",
+               dbesc(NETWORK_FACEBOOK)
+       );
+       if(! count($qi))
+               return;
+
+       require_once('include/queue_fn.php');
+
+       foreach($qi as $x) {
+               if($x['network'] !== NETWORK_FACEBOOK)
+                       continue;
+
+               logger('facebook_queue: run');
+
+               $r = q("SELECT `user`.* FROM `user` LEFT JOIN `contact` on `contact`.`uid` = `user`.`uid` 
+                       WHERE `contact`.`self` = 1 AND `contact`.`id` = %d LIMIT 1",
+                       intval($x['cid'])
+               );
+               if(! count($r))
+                       continue;
+
+               $user = $r[0];
+
+               $appid  = get_config('facebook', 'appid'  );
+               $secret = get_config('facebook', 'appsecret' );
+
+               if($appid && $secret) {
+                       $fb_post   = intval(get_pconfig($user['uid'],'facebook','post'));
+                       $fb_token  = get_pconfig($user['uid'],'facebook','access_token');
+
+                       if($fb_post && $fb_token) {
+                               logger('facebook_queue: able to post');
+                               require_once('library/facebook.php');
+
+                               $z = unserialize($x['content']);
+                               $item = $z['item'];
+                               $j = post_url($z['url'],$z['post']);
+
+                               $retj = json_decode($j);
+                               if($retj->id) {
+                                       q("UPDATE `item` SET `extid` = '%s' WHERE `id` = %d LIMIT 1",
+                                               dbesc('fb::' . $retj->id),
+                                               intval($item)
+                                       );
+                                       logger('facebook_queue: success: ' . $j); 
+                                       remove_queue_item($x['id']);
+                               }
+                               else {
+                                       logger('facebook_queue: failed: ' . $j);
+                                       update_queue_time($x['id']);
+                               }
+                       }
+               }
+       }
+}
+
+
+/**
+ * @return bool|string
+ */
+function fbpost_get_app_access_token() {
+
+       $acc_token = get_config('facebook','app_access_token');
+
+       if ($acc_token !== false) return $acc_token;
+
+       $appid = get_config('facebook','appid');
+       $appsecret = get_config('facebook', 'appsecret');
+
+       if ($appid === false || $appsecret === false) {
+               logger('fb_get_app_access_token: appid and/or appsecret not set', LOGGER_DEBUG);
+               return false;
+       }
+       logger('https://graph.facebook.com/oauth/access_token?client_id=' . $appid . '&client_secret=' . $appsecret . '&grant_type=client_credentials', LOGGER_DATA);
+       $x = fetch_url('https://graph.facebook.com/oauth/access_token?client_id=' . $appid . '&client_secret=' . $appsecret . '&grant_type=client_credentials');
+
+       if(strpos($x,'access_token=') !== false) {
+               logger('fb_get_app_access_token: returned access token: ' . $x, LOGGER_DATA);
+
+               $token = str_replace('access_token=', '', $x);
+               if(strpos($token,'&') !== false)
+                       $token = substr($token,0,strpos($token,'&'));
+
+               if ($token == "") {
+                       logger('fb_get_app_access_token: empty token: ' . $x, LOGGER_DEBUG);
+                       return false;
+               }
+               set_config('facebook','app_access_token',$token);
+               return $token;
+       } else {
+               logger('fb_get_app_access_token: response did not contain an access_token: ' . $x, LOGGER_DATA);
+               return false;
+       }
+}
+
+function fbpost_cron($a,$b) {
+       $last = get_config('facebook','last_poll');
+
+       $poll_interval = intval(get_config('facebook','poll_interval'));
+       if(! $poll_interval)
+               $poll_interval = FACEBOOK_DEFAULT_POLL_INTERVAL;
+
+       if($last) {
+               $next = $last + ($poll_interval * 60);
+               if($next > time()) {
+                       logger('facebook: poll intervall not reached');
+                       return;
+               }
+       }
+       logger('facebook: cron_start');
+
+       $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'facebook' AND `k` = 'mirror_posts' AND `v` = '1' ORDER BY RAND() ");
+       if(count($r)) {
+               foreach($r as $rr) {
+                       logger('facebook: fetching for user '.$rr['uid']);
+                       fbpost_fetchwall($a, $rr['uid']);
+               }
+       }
+
+       logger('facebook: cron_end');
+
+       set_config('facebook','last_poll', time());
+}
+
+function fbpost_fetchwall($a, $uid) {
+       $access_token = get_pconfig($uid,'facebook','access_token');
+       $post_to_page = get_pconfig($uid,'facebook','post_to_page');
+       $lastcreated = get_pconfig($uid,'facebook','last_created');
+
+       if ((int)$post_to_page == 0)
+               $post_to_page = "me";
+
+       $url = "https://graph.facebook.com/".$post_to_page."/feed?access_token=".$access_token;
+
+       $first_time = ($lastcreated == "");
+
+       if ($lastcreated != "")
+               $url .= "&since=".urlencode($lastcreated);
+
+       $feed = fetch_url($url);
+       $data = json_decode($feed);
+
+       if (!is_array($data->data))
+               return;
+
+       $items = array_reverse($data->data);
+
+       foreach ($items as $item) {
+               if ($item->created_time > $lastcreated)
+                       $lastcreated = $item->created_time;
+
+               if ($first_time)
+                       continue;
+
+               if ($item->application->id == get_config('facebook','appid'))
+                       continue;
+
+               if(isset($item->privacy) && ($item->privacy->value !== 'EVERYONE') && ($item->privacy->value !== ''))
+                       continue;
+
+               if (($post_to_page != $item->from->id) AND ((int)$post_to_page != 0))
+                       continue;
+
+               $_SESSION["authenticated"] = true;
+               $_SESSION["uid"] = $uid;
+
+               $_REQUEST["type"] = "wall";
+               $_REQUEST["api_source"] = true;
+               $_REQUEST["profile_uid"] = $uid;
+               $_REQUEST["source"] = "Facebook";
+
+               $_REQUEST["body"] = (isset($item->message) ? escape_tags($item->message) : '');
+
+               if(isset($item->name) and isset($item->link))
+                       $_REQUEST["body"] .= "\n\n[bookmark=".$item->link."]".$item->name."[/bookmark]";
+               elseif (isset($item->name))
+                       $_REQUEST["body"] .= "\n\n[b]" . $item->name."[/b]";
+
+               /*if(isset($item->caption)) {
+                       if(!isset($item->name) and isset($item->link))
+                               $_REQUEST["body"] .= "\n\n[bookmark=".$item->link."]".$item->caption."[/bookmark]";
+                       //else
+                       //      $_REQUEST["body"] .= "[i]" . $item->caption."[/i]\n";
+                       }
+
+                       if(!isset($item->caption) and !isset($item->name)) {
+                               if (isset($item->link))
+                                       $_REQUEST["body"] .= "\n[url]".$item->link."[/url]\n";
+                               else
+                                       $_REQUEST["body"] .= "\n";
+               }*/
+
+               $quote = "";
+               if(isset($item->description) and ($item->type != "photo"))
+                       $quote = $item->description;
+
+               if(isset($item->caption) and ($item->type == "photo"))
+                       $quote = $item->caption;
+
+               //if (isset($item->properties))
+               //      foreach ($item->properties as $property)
+               //              $quote .= "\n".$property->name.": [url=".$property->href."]".$property->text."[/url]";
+
+               if ($quote)
+                       $_REQUEST["body"] .= "\n[quote]".$quote."[/quote]";
+
+               // Only import the picture when the message is no video
+               // oembed display a picture of the video as well
+               if ($item->type != "video") {
+               //if (($item->type != "video") and ($item->type != "photo")) {
+                       if(isset($item->picture) && isset($item->link))
+                               $_REQUEST["body"] .= "\n".'[url='.$item->link.'][img]'.fpost_cleanpicture($item->picture).'[/img][/url]';
+                       else {
+                               if (isset($item->picture))
+                                       $_REQUEST["body"] .= "\n".'[img]'.fpost_cleanpicture($item->picture).'[/img]';
+                               // if just a link, it may be a wall photo - check
+                               if(isset($item->link))
+                                       $_REQUEST["body"] .= fbpost_get_photo($uid,$item->link);
+                       }
+               }
+
+               /*if (($datarray['app'] == "Events") and isset($item->actions))
+                       foreach ($item->actions as $action)
+                               if ($action->name == "View")
+                                       $_REQUEST["body"] .= " [url=".$action->link."]".$item->story."[/url]";
+               */
+
+               if(trim($_REQUEST["body"]) == '') {
+                       logger('facebook: empty body '.$item->id.' '.print_r($item, true));
+                       continue;
+               }
+
+               $_REQUEST["body"] = trim($_REQUEST["body"]);
+
+               if (isset($item->place)) {
+                       if ($item->place->name or $item->place->location->street or
+                               $item->place->location->city or $item->place->location->country) {
+                               $_REQUEST["location"] = '';
+                               if ($item->place->name)
+                                       $_REQUEST["location"] .= $item->place->name;
+                               if ($item->place->location->street)
+                                       $_REQUEST["location"] .= " ".$item->place->location->street;
+                               if ($item->place->location->city)
+                                       $_REQUEST["location"] .= " ".$item->place->location->city;
+                               if ($item->place->location->country)
+                                       $_REQUEST["location"] .= " ".$item->place->location->country;
+
+                               $_REQUEST["location"] = trim($_REQUEST["location"]);
+                       }
+                       if ($item->place->location->latitude and $item->place->location->longitude)
+                               $_REQUEST["coord"] = substr($item->place->location->latitude, 0, 8)
+                                               .' '.substr($item->place->location->longitude, 0, 8);
+               }
+
+               //print_r($_REQUEST);
+               logger('facebook: posting for user '.$uid);
+
+               require_once('mod/item.php');
+               item_post($a);
+       }
+
+       set_pconfig($uid,'facebook','last_created', $lastcreated);
+}
+
+function fbpost_get_photo($uid,$link) {
+       $access_token = get_pconfig($uid,'facebook','access_token');
+       if(! $access_token || (! stristr($link,'facebook.com/photo.php')))
+               return "";
+
+       $ret = preg_match('/fbid=([0-9]*)/',$link,$match);
+       if($ret)
+               $photo_id = $match[1];
+       else
+               return "";
+
+       $x = fetch_url('https://graph.facebook.com/'.$photo_id.'?access_token='.$access_token);
+       $j = json_decode($x);
+       if($j->picture)
+               return "\n\n".'[url='.$link.'][img]'.fpost_cleanpicture($j->picture).'[/img][/url]';
+
+       return "";
+}
+
+function fpost_cleanpicture($image) {
+
+       if (strpos($image, ".fbcdn.net/") and (substr($image, -6) == "_s.jpg"))
+               $image = substr($image, 0, -6)."_n.jpg";
+
+       $queryvar = fbpost_parse_query($image);
+       if ($queryvar['url'] != "")
+               $image = urldecode($queryvar['url']);
+
+       return $image;
+}
+
+function fbpost_parse_query($var) {
+       /**
+        *  Use this function to parse out the query array element from
+        *  the output of parse_url().
+       */
+       $var  = parse_url($var, PHP_URL_QUERY);
+       $var  = html_entity_decode($var);
+       $var  = explode('&', $var);
+       $arr  = array();
+
+       foreach($var as $val) {
+               $x          = explode('=', $val);
+               $arr[$x[0]] = $x[1];
+       }
+
+       unset($val, $x, $var);
+       return $arr;
+}
diff --git a/fortunate.tgz b/fortunate.tgz
new file mode 100644 (file)
index 0000000..a2dd39d
Binary files /dev/null and b/fortunate.tgz differ
diff --git a/fortunate/README b/fortunate/README
new file mode 100644 (file)
index 0000000..8297cf4
--- /dev/null
@@ -0,0 +1,7 @@
+This addon requires a fortune server. You may use the DB supplied here to create one.
+
+gunzip the fortunate.sql.gz and import into your database.
+Copy cookie.php to the top level Friendica directory.
+Edit fortunate.php and change FORTUNATE_SERVER definition to your hostname. Change the http in that file to https if your server doesn't support http. 
+
+Many additional options are available if you examine cookie.php - a clever developer can provide a settings page to tailor this to one's liking. Also several languages are supported, and it would be convenient to set this to the current Friendica language if that is amongst those supported.  
\ No newline at end of file
diff --git a/fortunate/cookie.php b/fortunate/cookie.php
new file mode 100644 (file)
index 0000000..0acfa23
--- /dev/null
@@ -0,0 +1,349 @@
+<?php
+
+set_time_limit(0);
+error_reporting(0);
+require(".htconfig.php");
+$db = @new mysqli($db_host,$db_user,$db_pass,$db_data);
+
+header( "Content-type: text/html; charset=utf-8");
+header( "Last-Modified: " . gmdate( "D, j M Y H:i:s" ) . " GMT" );
+header( "Expires: " . gmdate( "D, j M Y H:i:s", time() ) . " GMT" );
+header( "Cache-Control: no-store, no-cache, must-revalidate" ); // HTTP/1.1
+header( "Cache-Control: post-check=0, pre-check=0", FALSE );
+header( "Pragma: no-cache" ); // HTTP/1.0
+
+$lang = 'en';
+
+$offensive = $_GET['off'];
+if($offensive == 'o')
+  $adult = 2;
+elseif($offensive == 'a')
+  $adult = 1;
+else
+  $adult = 0;
+
+$length = (($_GET['length']) ? intval($_GET['length']) : 0);
+$numlines = ((intval($_GET['numlines'])) ? intval($_GET['numlines']) : 0); 
+$cat = (($_GET['cat'] == '1') ? 1 : 0);
+$equal = (($_GET['equal'] == '1') ? 1 : 0);
+$stats = (($_GET['stats'] == '1') ? 1 : 0);
+
+if(strlen($_GET['lang']))
+  $lang = @$db->real_escape_string($_GET['lang']);
+
+if(strlen($_GET['pattern']))
+  $pattern = @$db->real_escape_string(urldecode($_GET['pattern']));
+
+if(strlen($_GET['regex']))
+  $regex = @$db->real_escape_string(urldecode($_GET['regex']));
+
+if(strlen($_GET['db']))
+  $table = @$db->real_escape_string(urldecode($_GET['db']));
+else
+  $table = '';
+
+if($length < 0)
+  $length = 0;
+if($numlines < 0)
+  $numlines = 0;
+
+function do_query($table,$length,$numlines,$adult,$cat,$limit,$lang,$pattern,$regex,$equal) {
+  global $db;
+  $rnd = mt_rand();
+  $r = array();
+
+  $typesql   = (($table)  ? " WHERE `category` = '$table' " : " WHERE 1 ");
+  $lengthsql = (($length) ? " AND LENGTH(`text`) < $length " : "" );
+
+  if($adult == 2)
+    $adultsql  = " AND offensive = 1 ";
+  elseif($adult == 1)
+    $adultsql = "";
+  else
+    $adultsql = " AND offensive = 0 ";
+
+
+  if($numlines)
+    $lengthsql .=
+    " AND (LENGTH(`text`) - LENGTH(REPLACE(`text`,\"\n\",\"\"))) <= $numlines ";
+
+  $langsql = " AND lang = '$lang' ";
+
+  $patsql = '';
+  if(strlen($pattern))
+    $patsql = " AND MATCH text AGAINST ('$pattern' IN BOOLEAN MODE) ";
+
+  $regexsql = '';
+  if(strlen($regex))
+    $regexsql = " AND text REGEXP '$regex' ";
+
+  $eqsql = '';
+
+  if($equal) {
+    $catsavail = array();
+    $res = @$db->query("SELECT DISTINCT ( `category` ) FROM `fortune` 
+                           $typesql
+                           $adultsql
+                           $lengthsql
+                           $langsql
+                           $patsql 
+                           $regexsql ");
+    if($res->num_rows) {
+      while($x = $res->fetch_array(MYSQL_ASSOC))
+        $catsavail[] = $x['category'];
+    
+      $eqsql = " AND `category` = '"
+        . $catsavail[mt_rand(0,$res->num_rows - 1)] . "' ";
+   }
+  }
+
+  $result = @$db->query("SELECT `text`, `category` FROM `fortune` 
+                         $typesql
+                         $adultsql
+                         $lengthsql
+                         $langsql
+                         $patsql
+                         $regexsql
+                         $eqsql
+                         ORDER BY RAND($rnd) 
+                         LIMIT $limit");
+
+  if($result->num_rows) {
+    while($x = $result->fetch_array(MYSQL_ASSOC))
+      $r[] = fortune_to_html($x['text'])
+        .(($cat) ? "<br />[{$x['category']}]<br />" : "");
+  }
+  return $r;
+}
+
+
+function do_stats($table,$length,$numlines,$adult,$cat,$limit,$lang,$pattern,$regex,$equal) {
+  global $db;
+  $rnd = mt_rand();
+  $r = array();
+
+  $typesql   = (($table)  ? " WHERE `category` = '$table' " : " WHERE 1 ");
+  $lengthsql = (($length) ? " AND LENGTH(`text`) < $length " : "" );
+
+  if($adult == 2)
+    $adultsql  = " AND offensive = 1 ";
+  elseif($adult == 1)
+    $adultsql = "";
+  else
+    $adultsql = " AND offensive = 0 ";
+
+
+  if($numlines)
+    $lengthsql .=
+    " AND (LENGTH(`text`) - LENGTH(REPLACE(`text`,\"\n\",\"\"))) <= $numlines ";
+
+  $langsql = " AND lang = '$lang' ";
+
+  $patsql = '';
+  if(strlen($pattern))
+    $patsql = " AND MATCH text AGAINST ('$pattern' IN BOOLEAN MODE) ";
+
+  $regexsql = '';
+  if(strlen($regex))
+    $regexsql = " AND text REGEXP '$regex' ";
+
+  $eqsql = '';
+
+  $result = @$db->query("SELECT `text`, `category` FROM `fortune` 
+                         $typesql
+                         $adultsql
+                         $lengthsql
+                         $langsql
+                         $patsql
+                         $regexsql
+                         $eqsql");
+
+
+   echo '<br />' . $result->num_rows . ' matching quotations.<br />';
+
+
+   $res = @$db->query("SELECT DISTINCT ( `category` ) FROM `fortune` 
+                           $typesql
+                           $adultsql
+                           $lengthsql
+                           $langsql
+                           $patsql 
+                           $regexsql ");
+    if($res->num_rows) {
+      echo '<br />Matching Databases:<br />';
+      while($x = $res->fetch_array(MYSQL_ASSOC))
+        echo $x['category'].'<br />';
+    
+   }
+   else
+     echo '<br />No matching databases using those search parameters - please refine your options.<br />';
+   
+
+}
+
+
+function fortune_to_html($s) {
+
+  // First pass - escape all the HTML entities, and while we're at it
+  // get rid of any MS-DOS end-of-line characters and expand tabs to
+  // 8 non-breaking spaces, and translate linefeeds to <br />.
+  // We also get rid of ^G which used to sound the terminal beep or bell
+  // on ASCII terminals and were humourous in some fortunes.
+  // We could map these to autoplay a short sound file but browser support
+  // is still sketchy and then there's the issue of where to locate the
+  // URL, and a lot of people find autoplay sounds downright annoying.
+  // So for now, just remove them.
+
+  $s = str_replace(
+    array("&",
+          "<",
+          ">",
+          '"',
+          "\007",
+          "\t",
+          "\r",
+          "\n"),
+
+    array("&amp;",
+          "&lt;",
+          "&gt;",
+          "&quot;",
+          "",
+          "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;",
+          "",
+          "<br />"),
+    $s);
+  // Replace pseudo diacritics
+  // These were used to produce accented characters. For instance an accented
+  // e would have been encoded by '^He - the backspace moving the cursor
+  // backward so both the single quote and the e would appear in the same
+  // character position. Umlauts were quite clever - they used a double quote
+  // as the accent mark over a normal character.
+
+  $s = preg_replace("/'\010([a-zA-Z])/","&\\1acute;",$s);
+  $s = preg_replace("/\&quot;\010([a-zA-Z])/","&\\1uml;",$s);
+  $s = preg_replace("/\`\010([a-zA-Z])/","&\\1grave;",$s);
+  $s = preg_replace("/\^\010([a-zA-Z])/","&\\1circ;",$s);
+  $s = preg_replace("/\~\010([a-zA-Z])/","&\\1tilde;",$s);
+
+  // Ignore multiple underlines for the same character. These were
+  // most useful when sent to a line printer back in the day as it
+  // would type over the same character a number of times making it
+  // much darker (e.g. bold). I think there are only one or two
+  // instances of this in the current (2008) fortune cookie database.
+
+  $s = preg_replace("/(_\010)+/","_\010",$s);
+  // Map the characters which sit underneath a backspace.
+  // If you can come up with a regex to do all of the following
+  // madness  - be my guest.
+  // It's not as simple as you think. We need to take something
+  // that has been backspaced over an arbitrary number of times
+  // and wrap a forward looking matching number of characters in
+  // HTML, whilst deciding if it's intended as an underline or
+  // strikeout sequence.
+
+  // Essentially we produce a string of '1' and '0' characters
+  // the same length as the source text.
+  // Any position which is marked '1' has been backspaced over.
+
+  $cursor = 0;
+  $dst = $s;
+  $bs_found = false;
+  for($x = 0; $x < strlen($s); $x ++) {
+    if($s[$x] == "\010" && $cursor) {
+      $bs_found = true;
+      $cursor --;
+      $dst[$cursor] = '1';
+      $dst[$x] = '0';
+      $continue;
+    }
+    else {
+      if($bs_found) {
+        $bs_found = false;
+        $cursor = $x;
+      }
+      $dst[$cursor] = '0';
+      $cursor ++;
+    }
+
+  }
+
+  $out = '';
+  $strike = false;
+  $bold = false;
+
+  // Underline sequence, convert to bold to avoid confusion with links.
+  // These were generally used for emphasis so it's a reasonable choice.
+  // Please note that this logic will fail if there is an underline sequence
+  // and also a strikeout sequence in the same fortune.
+
+  if(strstr($s,"_\010")) {
+    $len = 0;
+    for($x = 0; $x < strlen($s); $x ++) {
+      if($dst[$x] == '1') {
+        $len ++;
+        $bold = true;
+      }
+      else {
+        if($bold) {
+          $out .= '<strong>';
+          while($s[$x] == "\010")
+             $x ++;
+          $out .= substr($s,$x,$len);
+          $out .= '</strong>';
+          $x = $x + $len - 1;
+          $len = 0;
+          $bold = false;
+        }
+        else
+          $out .= $s[$x];
+      }
+    }
+  }
+
+  // These aren't seen very often these days - simulation of
+  // backspace/replace. You could occasionally see the original text
+  // on slower terminals before it got replaced. Once modems reached
+  // 4800/9600 baud in the late 70's and early 80's the effect was
+  // mostly lost - but if you find a really old fortune file you might
+  // encounter a few of these.
+
+  else {
+    for($x = 0; $x < strlen($s); $x ++) {
+      if($dst[$x] == '1') {
+        if($strike)
+          $out .= $s[$x];
+        else
+          $out .= '<strike>'.$s[$x];
+        $strike = true;
+      }
+      else {
+        if($strike)
+          $out .= '</strike>';
+        $strike = false;
+        $out .= $s[$x];
+      }
+    }
+  }
+
+  // Many of the underline sequences are also wrapped in asterisks,
+  // which was yet another way of marking ASCII as 'bold'.
+  // So if it's an underline sequence, and there are asterisks
+  // on both ends, strip the asterisks as we've already emboldened the text.
+
+  $out = preg_replace('/\*(<strong>[^<]*<\/strong>)\*/',"\\1",$out);
+
+  // Finally, remove the backspace characters which we don't need anymore.
+
+  return str_replace("\010","",$out);
+}
+
+$result1 = do_query($table,$length,$numlines,$adult,$cat,1,$lang,$pattern,$regex,$equal);
+
+if(count($result1))
+  echo $result1[0];
+
+if($stats)
+  do_stats($table,$length,$numlines,$adult,$cat,1,$lang,$pattern,$regex,$equal);
+
+
diff --git a/fortunate/fortunate.css b/fortunate/fortunate.css
new file mode 100644 (file)
index 0000000..61813b7
--- /dev/null
@@ -0,0 +1,7 @@
+.fortunate {
+       margin-top: 25px;
+       margin-left: 100px;
+       margin-bottom: 25px;
+       color: #000088;
+       font-size: 14px;
+}
\ No newline at end of file
diff --git a/fortunate/fortunate.php b/fortunate/fortunate.php
new file mode 100644 (file)
index 0000000..427d620
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Name: Fortunate
+ * Description: Add a random fortune cookie at the bottom of every pages. [Requires manual confguration.]
+ * Version: 1.0
+ * Author: Mike Macgirvin <http://macgirvin.com/profile/mike>
+ */
+
+// IMPORTANT: SET THIS to your fortunate server
+
+define ('FORTUNATE_SERVER', 'hostname.com');
+
+function fortunate_install() {
+       register_hook('page_end', 'addon/fortunate/fortunate.php', 'fortunate_fetch');
+       if(FORTUNATE_SERVER == 'hostname.com' && is_site_admin()) {
+               notice('Fortunate plugin requires configuration. See README');
+       }
+}
+
+function fortunate_uninstall() {
+       unregister_hook('page_end', 'addon/fortunate/fortunate.php', 'fortunate_fetch');
+}
+
+
+function fortunate_fetch(&$a,&$b) {
+
+       $a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="' 
+               . $a->get_baseurl() . '/addon/fortunate/fortunate.css' . '" media="all" />' . "\r\n";
+
+       if(FORTUNATE_SERVER != 'hostname.com') {
+               $s = fetch_url('http://' . FORTUNATE_SERVER . '/cookie.php?numlines=2&equal=1&rand=' . mt_rand());
+               $b .= '<div class="fortunate">' . $s . '</div>';
+       }
+}
+
diff --git a/fortunate/fortunemod.sql.gz b/fortunate/fortunemod.sql.gz
new file mode 100644 (file)
index 0000000..2ce0e55
Binary files /dev/null and b/fortunate/fortunemod.sql.gz differ
diff --git a/forumdirectory.tgz b/forumdirectory.tgz
new file mode 100644 (file)
index 0000000..9f163de
Binary files /dev/null and b/forumdirectory.tgz differ
diff --git a/forumdirectory/forumdirectory.css b/forumdirectory/forumdirectory.css
new file mode 100644 (file)
index 0000000..c3c8485
--- /dev/null
@@ -0,0 +1,67 @@
+
+section .forumdirectory-item dl {
+  height: auto;
+  overflow: auto;      
+}
+
+section .forumdirectory-item dt {
+  float: left;
+  margin-left: 0px;
+  text-align: right;
+  color: #999;
+}
+section .forumdirectory-item dd {
+  float: left;
+  margin-left: 5px;
+}
+.forumdirectory-profile-wrapper {
+  float: left;
+  /*max-height: 178px; */
+  overflow: hidden;
+  width: 500px;
+  margin: 0px 20px;
+}
+.forumdirectory-copy-wrapper {
+  float: left;
+  overflow: hidden;    
+}
+
+.forumdirectory-item {
+  float: left;
+  width: 800px;
+ /* height: 200px; */
+  box-shadow: 8px 8px 4px #000;
+  margin-top: 30px;
+  border: solid 1px #222;
+}
+section .forumdirectory-photo-wrapper {
+  float: left;
+  height: 200px;
+  width: 165px;        
+}
+
+.forumcontact-name {
+  font-size: 18px;
+  font-weight: bold;
+  margin-bottom: -3px;
+  text-align: left;
+}
+
+.page-type {
+  font-size: 10px;
+  font-style: italic;
+}
+.directory-detailscolumn-wrapper {
+  float: left; 
+  width: 305px;
+  margin-right: 10px;  
+}
+.directory-profile-wrapper dl {
+  margin-top: 3px;
+  margin-bottom: 3px;
+}
+.directory-profile-title {
+  font-weight: bold;
+  margin-bottom: 3px;
+  font-size: 14px;
+} 
diff --git a/forumdirectory/forumdirectory.php b/forumdirectory/forumdirectory.php
new file mode 100644 (file)
index 0000000..f4292c6
--- /dev/null
@@ -0,0 +1,204 @@
+<?php
+/**
+* Name: Forum Directory
+* Description: Add a directory of forums hosted on your server, with verbose descriptions.
+* Version: 1.0
+* Author: Thomas Willingham <https://beardyunixer.com/profile/beardyunixer>
+*/
+
+function forumdirectory_install() {
+register_hook('app_menu', 'addon/forumdirectory/forumdirectory.php', 'forumdirectory_app_menu');
+}
+
+function forumdirectory_uninstall() {
+unregister_hook('app_menu', 'addon/forumdirectory/forumdirectory.php', 'forumdirectory_app_menu');
+}
+
+function forumdirectory_module() {
+return;
+}
+
+function forumdirectory_app_menu($a,&$b) {
+$b['app_menu'][] = '<div class="app-title"><a href="forumdirectory">' . t('Forum Directory') . '</a></div>';
+}
+
+function forumdirectory_init(&$a) {
+       $a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="'.$a->get_baseurl().'/addon/forumdirectory/forumdirectory.css" media="all" />';
+
+       $a->set_pager_itemspage(60);
+
+       if(local_user()) {
+               require_once('include/contact_widgets.php');
+
+               $a->page['aside'] .= findpeople_widget();
+
+       }
+       else
+               unset($_SESSION['theme']);
+
+
+}
+
+
+function forumdirectory_post(&$a) {
+       if(x($_POST,'search'))
+               $a->data['search'] = $_POST['search'];
+}
+
+
+
+function forumdirectory_content(&$a) {
+
+       if((get_config('system','block_public')) && (! local_user()) && (! remote_user())) {
+               notice( t('Public access denied.') . EOL);
+               return;
+       }
+
+       $o = '';
+       nav_set_selected('directory');
+
+       if(x($a->data,'search'))
+               $search = notags(trim($a->data['search']));
+       else
+               $search = ((x($_GET,'search')) ? notags(trim(rawurldecode($_GET['search']))) : '');
+
+       $tpl = get_markup_template('directory_header.tpl');
+
+       $globaldir = '';
+       $gdirpath = dirname(get_config('system','directory_submit_url'));
+       if(strlen($gdirpath)) {
+               $globaldir = '<ul><li><div id="global-directory-link"><a href="'
+               . zrl($gdirpath,true) . '">' . t('Global Directory') . '</a></div></li></ul>';
+       }
+
+       $admin = '';
+
+       $o .= replace_macros($tpl, array(
+               '$search' => $search,
+               '$globaldir' => $globaldir,
+               '$desc' => t('Find on this site'),
+               '$admin' => $admin,
+               '$finding' => (strlen($search) ? '<h4>' . t('Finding: ') . "'" . $search . "'" . '</h4>' : ""),
+               '$sitedir' => t('Site Directory'),
+               '$submit' => t('Find')
+       ));
+
+       if($search)
+               $search = dbesc($search);
+       $sql_extra = ((strlen($search)) ? " AND MATCH (`profile`.`name`, `user`.`nickname`, `pdesc`, `locality`,`region`,`country-name`,`gender`,`marital`,`sexual`,`about`,`romance`,`work`,`education`,`pub_keywords`,`prv_keywords` ) AGAINST ('$search' IN BOOLEAN MODE) " : "");
+
+       $publish = ((get_config('system','publish_all')) ? '' : " AND `publish` = 1 " );
+
+
+       $r = q("SELECT COUNT(*) AS `total` FROM `profile` LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid` WHERE `is-default` = 1 $publish AND `user`.`blocked` = 0 AND `page-flags` = 2 $sql_extra ");
+       if(count($r))
+               $a->set_pager_total($r[0]['total']);
+
+       $order = " ORDER BY `name` ASC "; 
+
+
+       $r = q("SELECT `profile`.*, `profile`.`uid` AS `profile_uid`, `user`.`nickname`, `user`.`timezone` , `user`.`page-flags` FROM `profile` LEFT JOIN `user` ON `user`.`uid` = `profile`.`uid` WHERE `is-default` = 1 $publish AND `user`.`blocked` = 0 AND `page-flags` = 2 $sql_extra $order LIMIT %d , %d ",
+               intval($a->pager['start']),
+               intval($a->pager['itemspage'])
+       );
+       if(count($r)) {
+
+               if(in_array('small', $a->argv))
+                       $photo = 'thumb';
+               else
+                       $photo = 'photo';
+
+               foreach($r as $rr) {
+
+
+                       $profile_link = $a->get_baseurl() . '/profile/' . ((strlen($rr['nickname'])) ? $rr['nickname'] : $rr['profile_uid']);
+               
+                       $pdesc = (($rr['pdesc']) ? $rr['pdesc'] . '<br />' : '');
+
+                       $details = '';
+                       if(strlen($rr['locality']))
+                               $details .= $rr['locality'];
+                       if(strlen($rr['region'])) {
+                               if(strlen($rr['locality']))
+                                       $details .= ', ';
+                               $details .= $rr['region'];
+                       }
+                       if(strlen($rr['country-name'])) {
+                               if(strlen($details))
+                                       $details .= ', ';
+                               $details .= $rr['country-name'];
+                       }
+                       if(strlen($rr['dob'])) {
+                               if(($years = age($rr['dob'],$rr['timezone'],'')) != 0)
+                                       $details .= '<br />' . t('Age: ') . $years ; 
+                       }
+                       if(strlen($rr['gender']))
+                               $details .= '<br />' . t('Gender: ') . $rr['gender'];
+
+                       if($rr['page-flags'] == PAGE_NORMAL)
+                               $page_type = "Personal Profile";
+                       if($rr['page-flags'] == PAGE_SOAPBOX)
+                               $page_type = "Fan Page";
+                       if($rr['page-flags'] == PAGE_COMMUNITY)
+                               $page_type = "Community Forum";
+                       if($rr['page-flags'] == PAGE_FREELOVE)
+                               $page_type = "Open Forum";
+                       if($rr['page-flags'] == PAGE_PRVGROUP)
+                               $page_type = "Private Group";
+
+                       $profile = $rr;
+
+                       if((x($profile,'address') == 1)
+                               || (x($profile,'locality') == 1)
+                               || (x($profile,'region') == 1)
+                               || (x($profile,'postal-code') == 1)
+                               || (x($profile,'country-name') == 1))
+                       $location = t('Location:');
+
+                       $gender = ((x($profile,'gender') == 1) ? t('Gender:') : False);
+
+                       $marital = ((x($profile,'marital') == 1) ?  t('Status:') : False);
+
+                       $homepage = ((x($profile,'homepage') == 1) ?  t('Homepage:') : False);
+
+                       $about = ((x($profile,'about') == 1) ?  t('About:') : False);
+                       
+#                      $tpl = file_get_contents( dirname(__file__).'/forumdirectory_item.tpl');
+                       $tpl = get_markup_template( 'forumdirectory_item.tpl', 'addon/forumdirectory/' );
+
+                       $entry = replace_macros($tpl,array(
+                               '$id' => $rr['id'],
+                               '$profile_link' => $profile_link,
+                               '$photo' => $a->get_cached_avatar_image($rr[$photo]),
+                               '$alt_text' => $rr['name'],
+                               '$name' => $rr['name'],
+                               '$details' => $pdesc . $details,
+                               '$page_type' => $page_type,
+                               '$profile' => $profile,
+                               '$location' => template_escape($location),
+                               '$gender'   => $gender,
+                               '$pdesc'        => $pdesc,
+                               '$marital'  => $marital,
+                               '$homepage' => $homepage,
+                               '$about' => $about,
+
+                       ));
+
+                       $arr = array('contact' => $rr, 'entry' => $entry);
+
+                       unset($profile);
+                       unset($location);
+
+                       $o .= $entry;
+
+               }
+
+               $o .= "<div class=\"directory-end\" ></div>\r\n";
+               $o .= paginate($a);
+
+       }
+       else
+               info( t("No entries \x28some entries may be hidden\x29.") . EOL);
+
+       return $o;
+}
diff --git a/forumdirectory/view/forumdirectory_item.tpl b/forumdirectory/view/forumdirectory_item.tpl
new file mode 100755 (executable)
index 0000000..e1bbffe
--- /dev/null
@@ -0,0 +1,42 @@
+
+<div class="forumdirectory-item" id="forumdirectory-item-$id" >
+       <div class="forumdirectory-photo-wrapper" id="forumdirectory-photo-wrapper-$id" > 
+               <div class="forumdirectory-photo" id="forumdirectory-photo-$id" >
+                       <a href="$profile_link" class="forumdirectory-profile-link" id="forumdirectory-profile-link-$id" >
+                               <img class="forumdirectory-photo-img photo" src="$photo" alt="$alt_text" title="$alt_text" />
+                       </a>
+               </div>
+       </div>
+       <div class="forumdirectory-profile-wrapper" id="forumdirectory-profile-wrapper-$id" >
+               <div class="contact-name" id="forumdirectory-name-$id">$name</div>
+               <div class="page-type">$page_type</div>
+               {{ if $pdesc }}<div class="forumdirectory-profile-title">$profile.pdesc</div>{{ endif }}
+       <div class="forumdirectory-detailcolumns-wrapper" id="forumdirectory-detailcolumns-wrapper-$id">
+               <div class="forumdirectory-detailscolumn-wrapper" id="forumdirectory-detailscolumn1-wrapper-$id">       
+                       {{ if $location }}
+                           <dl class="location"><dt class="location-label">$location</dt>
+                               <dd class="adr">
+                                       {{ if $profile.address }}<div class="street-address">$profile.address</div>{{ endif }}
+                                       <span class="city-state-zip">
+                                               <span class="locality">$profile.locality</span>{{ if $profile.locality }}, {{ endif }}
+                                               <span class="region">$profile.region</span>
+                                               <span class="postal-code">$profile.postal-code</span>
+                                       </span>
+                                       {{ if $profile.country-name }}<span class="country-name">$profile.country-name</span>{{ endif }}
+                               </dd>
+                               </dl>
+                       {{ endif }}
+
+                       {{ if $gender }}<dl class="mf"><dt class="gender-label">$gender</dt> <dd class="x-gender">$profile.gender</dd></dl>{{ endif }}
+                       </div>  
+                       <div class="forumdirectory-detailscolumn-wrapper" id="forumdirectory-detailscolumn2-wrapper-$id">       
+                               {{ if $marital }}<dl class="marital"><dt class="marital-label"><span class="heart">&hearts;</span>$marital</dt><dd class="marital-text">$profile.marital</dd></dl>{{ endif }}
+
+                               {{ if $homepage }}<dl class="homepage"><dt class="homepage-label">$homepage</dt><dd class="homepage-url"><a href="$profile.homepage" target="external-link">$profile.homepage</a></dd></dl>{{ endif }}
+                       </div>
+               </div>
+               <div class="forumdirectory-copy-wrapper" id="forumdirectory-copy-wrapper-$id" >
+                       {{ if $about }}<dl class="forumdirectory-copy"><dt class="forumdirectory-copy-label">$about</dt><dd class="forumdirectory-copy-data">$profile.about</dd></dl>{{ endif }}
+               </div>
+       </div>
+</div>
diff --git a/forumdirectory/view/smarty3/forumdirectory_item.tpl b/forumdirectory/view/smarty3/forumdirectory_item.tpl
new file mode 100644 (file)
index 0000000..66410ef
--- /dev/null
@@ -0,0 +1,42 @@
+
+<div class="forumdirectory-item" id="forumdirectory-item-{{$id}}" >
+       <div class="forumdirectory-photo-wrapper" id="forumdirectory-photo-wrapper-{{$id}}" > 
+               <div class="forumdirectory-photo" id="forumdirectory-photo-{{$id}}" >
+                       <a href="{{$profile_link}}" class="forumdirectory-profile-link" id="forumdirectory-profile-link-{{$id}}" >
+                               <img class="forumdirectory-photo-img photo" src="{{$photo}}" alt="{{$alt_text}}" title="{{$alt_text}}" />
+                       </a>
+               </div>
+       </div>
+       <div class="forumdirectory-profile-wrapper" id="forumdirectory-profile-wrapper-{{$id}}" >
+               <div class="contact-name" id="forumdirectory-name-{{$id}}">{{$name}}</div>
+               <div class="page-type">{{$page_type}}</div>
+               {{if $pdesc}}<div class="forumdirectory-profile-title">{{$profile.pdesc}}</div>{{/if}}
+       <div class="forumdirectory-detailcolumns-wrapper" id="forumdirectory-detailcolumns-wrapper-{{$id}}">
+               <div class="forumdirectory-detailscolumn-wrapper" id="forumdirectory-detailscolumn1-wrapper-{{$id}}">   
+                       {{if $location}}
+                           <dl class="location"><dt class="location-label">{{$location}}</dt>
+                               <dd class="adr">
+                                       {{if $profile.address}}<div class="street-address">{{$profile.address}}</div>{{/if}}
+                                       <span class="city-state-zip">
+                                               <span class="locality">{{$profile.locality}}</span>{{if $profile.locality}}, {{/if}}
+                                               <span class="region">{{$profile.region}}</span>
+                                               <span class="postal-code">{{$profile.postal-code}}</span>
+                                       </span>
+                                       {{if $profile.country-name}}<span class="country-name">{{$profile.country-name}}</span>{{/if}}
+                               </dd>
+                               </dl>
+                       {{/if}}
+
+                       {{if $gender}}<dl class="mf"><dt class="gender-label">{{$gender}}</dt> <dd class="x-gender">{{$profile.gender}}</dd></dl>{{/if}}
+                       </div>  
+                       <div class="forumdirectory-detailscolumn-wrapper" id="forumdirectory-detailscolumn2-wrapper-{{$id}}">   
+                               {{if $marital}}<dl class="marital"><dt class="marital-label"><span class="heart">&hearts;</span>{{$marital}}</dt><dd class="marital-text">{{$profile.marital}}</dd></dl>{{/if}}
+
+                               {{if $homepage}}<dl class="homepage"><dt class="homepage-label">{{$homepage}}</dt><dd class="homepage-url"><a href="{{$profile.homepage}}" target="external-link">{{$profile.homepage}}</a></dd></dl>{{/if}}
+                       </div>
+               </div>
+               <div class="forumdirectory-copy-wrapper" id="forumdirectory-copy-wrapper-{{$id}}" >
+                       {{if $about}}<dl class="forumdirectory-copy"><dt class="forumdirectory-copy-label">{{$about}}</dt><dd class="forumdirectory-copy-data">{{$profile.about}}</dd></dl>{{/if}}
+               </div>
+       </div>
+</div>
diff --git a/forumlist.tgz b/forumlist.tgz
new file mode 100644 (file)
index 0000000..8356d44
Binary files /dev/null and b/forumlist.tgz differ
diff --git a/forumlist/forumlist.css b/forumlist/forumlist.css
new file mode 100644 (file)
index 0000000..18c8e16
--- /dev/null
@@ -0,0 +1,22 @@
+
+#hide-forum-list {
+       opacity: 0.3;
+       filter:alpha(opacity=30);
+}
+
+#hide-forum-list:hover {
+       opacity: 1.0;
+       filter:alpha(opacity=100);
+}
+
+
+#forumlist-settings-label, #forumlist-random-label, #forumlist-profile-label, #forumlist-network-label {
+       float: left;
+       width: 200px;
+       margin-bottom: 25px;
+}
+
+#forumlist-max-forumlists, #forumlist-random, #forumlist-profile, #forumlist-network {
+       float: left;
+}
+
diff --git a/forumlist/forumlist.php b/forumlist/forumlist.php
new file mode 100644 (file)
index 0000000..95ae989
--- /dev/null
@@ -0,0 +1,182 @@
+<?php
+/**
+ * Name: ForumList
+ * Description: Shows list of subscribed community forums on network sidebar
+ * Version: 1.1
+ * Author: Mike Macgirvin <mike@macgirvin.com>
+ * based on pages plugin by
+ * Author: Michael Vogel <ike@piratenpartei.de>
+ *
+ */
+
+function forumlist_install() {
+       register_hook('network_mod_init', 'addon/forumlist/forumlist.php', 'forumlist_network_mod_init');
+       register_hook('plugin_settings', 'addon/forumlist/forumlist.php', 'forumlist_plugin_settings');
+       register_hook('plugin_settings_post', 'addon/forumlist/forumlist.php', 'forumlist_plugin_settings_post');
+       register_hook('profile_advanced', 'addon/forumlist/forumlist.php', 'forumlist_profile_advanced');
+
+}
+
+function forumlist_uninstall() {
+       unregister_hook('network_mod_init', 'addon/forumlist/forumlist.php', 'forumlist_network_mod_init');
+       unregister_hook('plugin_settings', 'addon/forumlist/forumlist.php', 'forumlist_plugin_settings');
+       unregister_hook('plugin_settings_post', 'addon/forumlist/forumlist.php', 'forumlist_plugin_settings_post');
+       unregister_hook('profile_advanced', 'addon/forumlist/forumlist.php', 'forumlist_profile_advanced');
+
+}
+
+
+function forumlist_getpage($uid,$showhidden = true,$randomise = false, $showprivate = false) {
+
+
+       $forumlist = array();
+
+       $order = (($showhidden) ? '' : " and hidden = 0 ");
+        $order .= (($randomise) ? ' order by rand() ' : ' order by name asc ');
+        $select = "`forum` = 1";
+        if ($showprivate) {
+            $select = "( `forum` = 1 OR `prv` = 1 )";
+        }
+
+       $contacts = q("SELECT `contact`.`id`, `contact`.`url`, `contact`.`name`, `contact`.`micro` from contact 
+                       WHERE `network`= 'dfrn' AND $select AND `uid` = %d
+                       and blocked = 0 and hidden = 0 and pending = 0 and archive = 0
+                       $order ",
+                       intval($uid)
+       );
+
+       // Look if the profile is a community page
+       foreach($contacts as $contact) {
+               $forumlist[] = array("url"=>$contact["url"], "name"=>$contact["name"], "id"=>$contact["id"], "micro"=>$contact['micro']);
+       }
+       return($forumlist);
+}
+
+function forumlist_network_mod_init($a,$b) {
+
+       if(! intval(get_pconfig(local_user(),'forumlist','show_on_network')))
+               return;
+
+       $a->page['htmlhead'] .= '<link rel="stylesheet"  type="text/css" href="' . $a->get_baseurl() . '/addon/forumlist/forumlist.css' . '" media="all" />' . "\r\n";
+
+       $forumlist = '<div id="forumlist-sidebar" class="widget">
+                       <div class="title tool">
+                       <h3>'.t("Forums").'</h3></div>';
+
+       $forumlist .= '<div id="hide-forum-list" class="fakelink" onclick="openClose(\'forum-list\');" >' 
+                               . t('show/hide') . '</div>'
+                               . '<div id="forum-list" style="display: none;">';
+
+
+       $randomise = intval(get_pconfig(local_user(),'forumlist','randomise'));
+
+       $contacts = forumlist_getpage($a->user['uid'],true,$randomise, true);
+
+       if(count($contacts)) {
+               foreach($contacts as $contact) {
+                       $forumlist .= '<div><a href="' . $a->get_baseurl() . '/redir/' . $contact["id"] . '" title="' . $contact['url'] . '" class="label sparkle" target="external-link"><img class="forumlist-img" height="20" width="20" src="' . $contact['micro'] .'" alt="' . $contact['url'] . '" /></a> <a href="' . $a->get_baseurl() . '/network?f=&cid=' . $contact['id'] . '" >' . $contact["name"]."</a></div>";
+               }
+       }
+       else {
+               $forumlist .= t('No forum subscriptions');
+       }
+               
+       $forumlist .= "</div></div>";
+       if (sizeof($contacts) > 0)
+               $a->page['aside'] = $forumlist . $a->page['aside'];
+}
+
+
+function forumlist_profile_advanced($a,&$b) {
+       $a->page['htmlhead'] .= '<link rel="stylesheet"  type="text/css" href="' . $a->get_baseurl() . '/addon/forumlist/forumlist.css' . '" media="all" />' . "\r\n";
+
+       $profile = intval(get_pconfig($a->profile['profile_uid'],'forumlist','show_on_profile'));
+       if(! $profile)
+               return;
+
+       $forumlist = '<div id="forumlist-profile">
+                       <div class="title">'.t("Forums:").'</div>
+                       <div id="profile-forumlist-list">';
+
+       // place holder in case somebody wants configurability
+       $show_total = 9999;
+
+       $randomise = true;
+
+       $contacts = forumlist_getpage($a->user['uid'],false,$randomise,false);
+
+       $total_shown = 0;
+       $more = false;
+
+       foreach($contacts as $contact) {
+               $forumlist .= micropro($contact,false,'forumlist-profile-advanced');
+               $total_shown ++;
+               if($total_shown == $show_total)
+                       break;
+       }
+       $forumlist .= '</div></div><div class="clear"></div>';
+
+       if(count($contacts) > 0)
+               $b .= $forumlist;
+
+}
+
+
+
+function forumlist_plugin_settings_post($a,$post) {
+       if(! local_user() || (! x($_POST,'forumlist-settings-submit')))
+               return;
+//     set_pconfig(local_user(),'forumlist','max_forumlists',intval($_POST['forumlist_max_forumlists']));
+       set_pconfig(local_user(),'forumlist','randomise',intval($_POST['forumlist_random']));
+       set_pconfig(local_user(),'forumlist','show_on_profile',intval($_POST['forumlist_profile']));
+       set_pconfig(local_user(),'forumlist','show_on_network',intval($_POST['forumlist_network']));
+
+       info( t('Forumlist settings updated.') . EOL);
+}
+
+
+function forumlist_plugin_settings(&$a,&$s) {
+
+       if(! local_user())
+               return;
+
+       /* Add our stylesheet to the forumlist so we can make our settings look nice */
+
+       $a->page['htmlhead'] .= '<link rel="stylesheet"  type="text/css" href="' . $a->get_baseurl() . '/addon/forumlist/forumlist.css' . '" media="all" />' . "\r\n";
+
+       /* Get the current state of our config variable */
+
+       $randomise = intval(get_pconfig(local_user(),'forumlist','randomise'));
+       $randomise_checked = (($randomise) ? ' checked="checked" ' : '');
+
+       $profile = intval(get_pconfig(local_user(),'forumlist','show_on_profile'));
+       $profile_checked = (($profile) ? ' checked="checked" ' : '');
+
+       $network = intval(get_pconfig(local_user(),'forumlist','show_on_network'));
+       $network_checked = (($network) ? ' checked="checked" ' : '');
+       
+       
+       /* Add some HTML to the existing form */
+
+       $s .= '<div class="settings-block">';
+       $s .= '<h3>' . t('Forumlist Settings') . '</h3>';
+       $s .= '<div id="forumlist-settings-wrapper">';
+       $s .= '<label id="forumlist-random-label" for="forumlist-random">' . t('Randomise forum list') . '</label>';
+       $s .= '<input id="forumlist-random" type="checkbox" name="forumlist_random" value="1" ' . $randomise_checked . '/>';
+       $s .= '<div class="clear"></div>';
+       $s .= '<label id="forumlist-profile-label" for="forumlist-profile">' . t('Show forums on profile page') . '</label>';
+       $s .= '<input id="forumlist-profile" type="checkbox" name="forumlist_profile" value="1" ' . $profile_checked . '/>';
+       $s .= '<div class="clear"></div>';
+       $s .= '<label id="forumlist-network-label" for="forumlist-network">' . t('Show forums on network page') . '</label>';
+       $s .= '<input id="forumlist-network" type="checkbox" name="forumlist_network" value="1" ' . $network_checked . '/>';
+       $s .= '<div class="clear"></div>';
+
+       $s .= '</div>';
+
+       /* provide a submit button */
+
+       $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="forumlist-settings-submit" class="settings-submit" value="' . t('Submit') . '" /></div></div>';
+
+}
+
+
diff --git a/fromapp.tgz b/fromapp.tgz
new file mode 100644 (file)
index 0000000..30d84e9
Binary files /dev/null and b/fromapp.tgz differ
diff --git a/fromapp/fromapp.css b/fromapp/fromapp.css
new file mode 100644 (file)
index 0000000..422624a
--- /dev/null
@@ -0,0 +1,14 @@
+
+
+
+#fromapp-label, #fromapp-force-label {
+       float: left;
+       width: 200px;
+       margin-bottom: 25px;
+}
+
+#fromapp-input, #fromapp-force {
+       float: left;
+}
+
+
diff --git a/fromapp/fromapp.php b/fromapp/fromapp.php
new file mode 100644 (file)
index 0000000..9a9fa12
--- /dev/null
@@ -0,0 +1,101 @@
+<?php
+/**
+ * Name: FromApp
+ * Description: Change the displayed application you are posting from
+ * Version: 1.0
+ * Author: Commander Zot
+ *
+ */
+
+
+function fromapp_install() {
+
+       register_hook('post_local', 'addon/fromapp/fromapp.php', 'fromapp_post_hook');
+       register_hook('plugin_settings', 'addon/fromapp/fromapp.php', 'fromapp_settings');
+       register_hook('plugin_settings_post', 'addon/fromapp/fromapp.php', 'fromapp_settings_post');
+
+       logger("installed fromapp");
+}
+
+
+function fromapp_uninstall() {
+
+       unregister_hook('post_local', 'addon/fromapp/fromapp.php', 'fromapp_post_hook');
+       unregister_hook('plugin_settings', 'addon/fromapp/fromapp.php', 'fromapp_settings');
+       unregister_hook('plugin_settings_post', 'addon/fromapp/fromapp.php', 'fromapp_settings_post');
+
+
+       logger("removed fromapp");
+}
+
+function fromapp_settings_post($a,$post) {
+       if(! local_user() || (! x($_POST,'fromapp-submit')))
+               return;
+
+       set_pconfig(local_user(),'fromapp','app',$_POST['fromapp-input']);
+       set_pconfig(local_user(),'fromapp','force',intval($_POST['fromapp-force']));
+
+       info( t('Fromapp settings updated.') . EOL);
+}
+
+function fromapp_settings(&$a,&$s) {
+
+       if(! local_user())
+               return;
+
+       /* Add our stylesheet to the page so we can make our settings look nice */
+
+       $a->page['htmlhead'] .= '<link rel="stylesheet"  type="text/css" href="' . $a->get_baseurl() . '/addon/fromapp/fromapp.css' . '" media="all" />' . "\r\n";
+
+       /* Get the current state of our config variable */
+
+       $fromapp = get_pconfig(local_user(),'fromapp','app');
+       if($fromapp === false)
+               $fromapp = '';
+
+       $force = intval(get_pconfig(local_user(),'fromapp','force'));
+
+       $force_enabled = (($force) ? ' checked="checked" ' : '');
+
+       
+       /* Add some HTML to the existing form */
+
+       $s .= '<div class="settings-block">';
+       $s .= '<h3>' . t('FromApp Settings') . '</h3>';
+       $s .= '<div id="fromapp-wrapper">';
+       $s .= '<label id="fromapp-label" for="fromapp-input">' . t('The application name you would like to show your posts originating from.') . '</label>';
+       $s .= '<input id="fromapp-input" type="text" name="fromapp-input" value="' . $fromapp . '" ' . '/>';
+       $s .= '<div class="clear"></div>';
+
+       $s .= '<label id="fromapp-force-label" for="fromapp-force">' . t('Use this application name even if another application was used.') . '</label>';
+       $s .= '<input id="fromapp-force" type="checkbox" name="fromapp-force" value="1" ' . $force_enabled . '/>';
+
+       $s .= '</div><div class="clear"></div>';
+
+       /* provide a submit button */
+
+       $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="fromapp-submit" class="settings-submit" value="' . t('Submit') . '" /></div></div>';
+
+}
+
+function fromapp_post_hook(&$a,&$item) {
+   if(! local_user())
+        return;
+
+    if(local_user() != $item['uid'])
+        return;
+
+    $app = get_pconfig(local_user(), 'fromapp', 'app');
+       $force = intval(get_pconfig(local_user(), 'fromapp','force'));
+
+    if(($app === false) || (! strlen($app)))
+        return;
+
+       if(strlen(trim($item['app'])) && (! $force))
+               return;
+
+       $apps = explode(',',$app);
+       $item['app'] = trim($apps[mt_rand(0,count($apps)-1)]);
+       return;
+
+}
\ No newline at end of file
diff --git a/fromgplus.tgz b/fromgplus.tgz
new file mode 100644 (file)
index 0000000..0a402b7
Binary files /dev/null and b/fromgplus.tgz differ
index cecbb2b9d17bec1d0893e8c14685ed2319e2a5d6..82a29f6635e414dcc9c6aef6b2e11beb48c3d4e6 100644 (file)
@@ -1 +1,15 @@
-This extension is a preparation of the upcoming import of items via Google+
+This extension fetches messages from a Google+ account and reshares it.
+
+You have to place the following config values in your .htconfig.php:
+
+$a->config['fromgplus']['key'] = "your key";
+$a->config['fromgplus']['poll_interval'] = 10;
+
+You need an API key for "Simple API Access". 
+
+- You go to https://code.google.com/apis/console/
+- Then you go to "Services" and activate "Google+ API".
+- After that you go to "API Access".
+- At the bottom of the page you see "Simple API Access".
+
+The value after "API key:" is the key that you need.
index 88d2622ff16fcf46306d47e919c336c082e4c5d5..5bd82ed86855cd0c205cfbd7c50c502465520254 100644 (file)
@@ -1,20 +1,24 @@
 <?php
 /**
  * Name: From GPlus
- * Description: Imports posts from a Google+ account and repeats them - not working by now
+ * Description: Imports posts from a Google+ account and repeats them
  * Version: 0.1
  * Author: Michael Vogel <ike@piratenpartei.de>
  *
  */
 
+define('FROMGPLUS_DEFAULT_POLL_INTERVAL', 30); // given in minutes
+
 function fromgplus_install() {
        register_hook('plugin_settings', 'addon/fromgplus/fromgplus.php', 'fromgplus_addon_settings');
        register_hook('plugin_settings_post', 'addon/fromgplus/fromgplus.php', 'fromgplus_addon_settings_post');
+       register_hook('cron', 'addon/fromgplus/fromgplus.php', 'fromgplus_cron');
 }
 
 function fromgplus_uninstall() {
        unregister_hook('plugin_settings', 'addon/fromgplus/fromgplus.php', 'fromgplus_addon_settings');
        unregister_hook('plugin_settings_post', 'addon/fromgplus/fromgplus.php', 'fromgplus_addon_settings_post');
+       unregister_hook('cron', 'addon/fromgplus/fromgplus.php', 'fromgplus_cron');
 }
 
 function fromgplus_addon_settings(&$a,&$s) {
@@ -55,129 +59,330 @@ function fromgplus_addon_settings_post(&$a,&$b) {
                info( t('Google+ Import Settings saved.') . EOL);
        }
 }
-/*
-function html2bbcode($html) {
+
+function fromgplus_cron($a,$b) {
+       $last = get_config('fromgplus','last_poll');
+
+        $poll_interval = intval(get_config('fromgplus','poll_interval'));
+        if(! $poll_interval)
+                $poll_interval = FROMGPLUS_DEFAULT_POLL_INTERVAL;
+
+        if($last) {
+                $next = $last + ($poll_interval * 60);
+                if($next > time()) {
+                       logger('fromgplus: poll intervall not reached');
+                        return;
+               }
+       }
+
+        logger('fromgplus: cron_start');
+
+        $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'fromgplus' AND `k` = 'enable' AND `v` = '1' ORDER BY RAND() ");
+        if(count($r)) {
+                foreach($r as $rr) {
+                       $account = get_pconfig($rr['uid'],'fromgplus','account');
+                       if ($account) {
+                       logger('fromgplus: fetching for user '.$rr['uid']);
+                               fromgplus_fetch($a, $rr['uid']);
+                       }
+               }
+       }
+
+        logger('fromgplus: cron_end');
+
+       set_config('fromgplus','last_poll', time());
+}
+
+function fromgplus_post($a, $uid, $source, $body, $location) {
+
+       //$uid = 2;
+
+       $body = trim($body);
+
+        if (substr($body, 0, 3) == "[b]") {
+                $pos = strpos($body, "[/b]");
+                $title = substr($body, 3, $pos-3);
+                $body = trim(substr($body, $pos+4));
+        } else
+                $title = "";
+
+       $_SESSION['authenticated'] = true;
+       $_SESSION['uid'] = $uid;
+
+       $_REQUEST['type'] = 'wall';
+       $_REQUEST['api_source'] = true;
+
+       $_REQUEST['profile_uid'] = $uid;
+       $_REQUEST['source'] = $source;
+
+       // $_REQUEST['verb']
+       // $_REQUEST['parent']
+       // $_REQUEST['parent_uri']
+
+       $_REQUEST['title'] = $title;
+       $_REQUEST['body'] = $body;
+       $_REQUEST['location'] = $location;
+
+        logger('fromgplus: posting for user '.$uid);
+
+       require_once('mod/item.php');
+       //print_r($_REQUEST);
+       item_post($a);
+}
+
+function fromgplus_html2bbcode($html) {
 
        $bbcode = html_entity_decode($html, ENT_QUOTES, 'UTF-8');
 
-       $bbcode = str_replace(array("\n"), array(""), $bbcode);
-       $bbcode = str_replace(array("<b>", "</b>"), array("[b]", "[/b]"), $bbcode);
-       $bbcode = str_replace(array("<i>", "</i>"), array("[i]", "[/i]"), $bbcode);
-       $bbcode = str_replace(array("<s>", "</s>"), array("[s]", "[/s]"), $bbcode);
-       $bbcode = str_replace(array("<br />"), array("\n"), $bbcode);
+       $bbcode = str_ireplace(array("\n"), array(""), $bbcode);
+       $bbcode = str_ireplace(array("<b>", "</b>"), array("[b]", "[/b]"), $bbcode);
+       $bbcode = str_ireplace(array("<i>", "</i>"), array("[i]", "[/i]"), $bbcode);
+       $bbcode = str_ireplace(array("<s>", "</s>"), array("[s]", "[/s]"), $bbcode);
+       $bbcode = str_ireplace(array("<br />"), array("\n"), $bbcode);
+       $bbcode = str_ireplace(array("<br/>"), array("\n"), $bbcode);
+       $bbcode = str_ireplace(array("<br>"), array("\n"), $bbcode);
 
        $bbcode = trim(strip_tags($bbcode));
        return($bbcode);
 }
 
-function friendicapost($post) {
-       global $friendica;
+function fromgplus_parse_query($var)
+ {
+       /**
+       *  Use this function to parse out the query array element from
+       *  the output of parse_url().
+       */
+       $var  = parse_url($var, PHP_URL_QUERY);
+       $var  = html_entity_decode($var);
+       $var  = explode('&', $var);
+       $arr  = array();
+
+       foreach($var as $val) {
+               $x          = explode('=', $val);
+               $arr[$x[0]] = $x[1];
+       }
+       unset($val, $x, $var);
+       return $arr;
+}
+
+function fromgplus_cleanupgoogleproxy($fullImage, $image) {
+
+       $preview = "/w".$fullImage->width."-h".$fullImage->height."/";
+       $preview2 = "/w".$fullImage->width."-h".$fullImage->height."-p/";
+       $fullImage = str_replace(array($preview, $preview2), array("/", "/"), $fullImage->url);
+
+       $preview = "/w".$image->width."-h".$image->height."/";
+       $preview2 = "/w".$image->width."-h".$image->height."-p/";
+       $image = str_replace(array($preview, $preview2), array("/", "/"), $image->url);
+
+               $cleaned = array();
+
+       $queryvar = fromgplus_parse_query($fullImage);
+       if ($queryvar['url'] != "")
+               $cleaned["full"] = urldecode($queryvar['url']);
+       else
+               $cleaned["full"] = $fullImage;
+       if (@exif_imagetype($cleaned["full"]) == 0)
+               $cleaned["full"] = "";
+
+       $queryvar = fromgplus_parse_query($image);
+       if ($queryvar['url'] != "")
+                       $cleaned["preview"] = urldecode($queryvar['url']);
+       else
+               $cleaned["preview"] = $image;
+       if (@exif_imagetype($cleaned["preview"]) == 0)
+               $cleaned["preview"] = "";
+
+       if ($cleaned["full"] == "") {
+               $cleaned["full"] = $cleaned["preview"];
+               $cleaned["preview"] = "";
+       }
+
+       if ($cleaned["full"] == $cleaned["preview"])
+               $cleaned["preview"] = "";
+
+       if ($cleaned["full"] == "")
+               if (@exif_imagetype($fullImage) != 0)
+                       $cleaned["full"] = $fullImage;
+
+       if ($cleaned["full"] == "")
+               if (@exif_imagetype($image) != 0)
+                       $cleaned["full"] = $fullImage;
 
-       $api = new Statusnet($friendica["user"], $friendica["pw"], "GooglePlus", $friendica["server"]);
-       $ret = $api->updateStatus($post);
-       $api->endSession();
+       return($cleaned);
 }
 
-function handleattachments($item) {
+function fromgplus_handleattachments($item) {
        $post = "";
+       $quote = "";
 
        foreach ($item->object->attachments as $attachment) {
                switch($attachment->objectType) {
                        case "video":
-                               //$post .= "\n\n[url=".$attachment->url."]".
-                               //              "[size=large][b]".html2bbcode($attachment->displayName)."[/b][/size][/url]\n";
-                               $post .= "\n\n[bookmark=".$attachment->url."]".html2bbcode($attachment->displayName)."[/bookmark]\n";
+                               $post .= "\n\n[bookmark=".$attachment->url."]".fromgplus_html2bbcode($attachment->displayName)."[/bookmark]\n";
 
-                               //if (strpos($attachment->embed->url, "youtube.com"))
-                               //      $post .= "[youtube]".$attachment->url."[/youtube]\n";
-                               //else
-                               ///     $post .= "[url=".$attachment->url."][img]".$attachment->image->url."[/img][/url]\n";
+                               /*$images = cleanupgoogleproxy($attachment->fullImage, $attachment->image);
+                               if ($images["preview"] != "")
+                                       $post .= "\n[url=".$images["full"]."][img]".$images["preview"]."[/img][/url]\n";
+                               elseif ($images["full"] != "")
+                                       $post .= "\n[img]".$images["full"]."[/img]\n";*/
 
-                               ///$post .= "[quote]".trim(html2bbcode($attachment->content))."[/quote]";
                                break;
 
                        case "article":
-                               //$post .= "\n\n[url=".$attachment->url."]".
-                               //              "[size=large][b]".html2bbcode($attachment->displayName)."[/b][/size][/url]\n";
-                               $post .= "\n\n[bookmark=".$attachment->url."]".html2bbcode($attachment->displayName)."[/bookmark]\n";
-                               $post .= "[quote]".trim(html2bbcode($attachment->content))."[/quote]";
+                               $post .= "\n\n[bookmark=".$attachment->url."]".fromgplus_html2bbcode($attachment->displayName)."[/bookmark]\n";
+
+                               $images = fromgplus_cleanupgoogleproxy($attachment->fullImage, $attachment->image);
+                               if ($images["preview"] != "")
+                                       $post .= "\n[url=".$images["full"]."][img]".$images["preview"]."[/img][/url]\n";
+                               elseif ($images["full"] != "")
+                                       $post .= "\n[img]".$images["full"]."[/img]\n";
+
+                               //$post .= "[quote]".trim(fromgplus_html2bbcode($attachment->content))."[/quote]";
+                               $quote = trim(fromgplus_html2bbcode($attachment->content));
+                               if ($quote != "")
+                                       $quote = "\n[quote]".$quote."[/quote]";
                                break;
 
                        case "photo":
-                               //$post .= "\n\n[url=".$attachment->fullImage->url."]".
-                               //              "[img]".$attachment->fullImage->url."[/img][/url]\n";
-                               $post .= "\n\n[img]".$attachment->fullImage->url."[/img]\n";
+                               $images = fromgplus_cleanupgoogleproxy($attachment->fullImage, $attachment->image);
+                               if ($images["preview"] != "")
+                                       $post .= "\n[url=".$images["full"]."][img]".$images["preview"]."[/img][/url]\n";
+                               elseif ($images["full"] != "")
+                                       $post .= "\n[img]".$images["full"]."[/img]\n";
+
                                if ($attachment->displayName != "")
-                                       $post .= html2bbcode($attachment->displayName)."\n";
+                                       $post .= fromgplus_html2bbcode($attachment->displayName)."\n";
                                break;
 
                        case "photo-album":
-                               $post .= "\n\n[url=".$attachment->url."]".
-                                               "[size=large][b]".html2bbcode($attachment->displayName)."[/b][/size][/url]\n";
+                               $post .= "\n\n[bookmark=".$attachment->url."]".fromgplus_html2bbcode($attachment->displayName)."[/bookmark]\n";
+
+                               $images = fromgplus_cleanupgoogleproxy($attachment->fullImage, $attachment->image);
+                               if ($images["preview"] != "")
+                                       $post .= "\n[url=".$images["full"]."][img]".$images["preview"]."[/img][/url]\n";
+                               elseif ($images["full"] != "")
+                                       $post .= "\n[img]".$images["full"]."[/img]\n";
+
                                break;
 
-                       default:
-                               print_r($attachment);
-                               die();
+                       case "album":
+                               foreach($attachment->thumbnails as $thumb) {
+                                       $preview = "/w".$thumb->image->width."-h".$thumb->image->height."/";
+                                       $preview2 = "/w".$thumb->image->width."-h".$thumb->image->height."-p/";
+                                       $image = str_replace(array($preview, $preview2), array("/", "/"), $thumb->image->url);
+
+                                       $post .= "\n[url=".$thumb->url."][img]".$image."[/img][/url]\n";
+                               }
                                break;
+                       case "audio":
+                               $post .= "\n\n[bookmark=".$attachment->url."]".fromgplus_html2bbcode($attachment->displayName)."[/bookmark]\n";
+                               break;
+                       //default:
+                       //      die($attachment->objectType);
                }
        }
-       return($post);
+       return($post.$quote);
 }
 
-$result = 
-file_get_contents("https://www.googleapis.com/plus/v1/people/".$google["id"]."/activities/public?alt=json&pp=1&key=".$google["key"]."&maxResults=".$google["maxfetch"]);
-$activities = json_decode($result);
+function fromgplus_fetch($a, $uid) {
+       $maxfetch = 20;
+
+       $account = get_pconfig($uid,'fromgplus','account');
+       $key = get_config('fromgplus','key');
 
-$state = array("lastid"=>'');
-if (file_exists($statefile))
-       $state = unserialize(file_get_contents($statefile));
+       $result = fetch_url("https://www.googleapis.com/plus/v1/people/".$account."/activities/public?alt=json&pp=1&key=".$key."&maxResults=".$maxfetch);
+       //$result = file_get_contents("google.txt");
+       //file_put_contents("google.txt", $result);
 
-$lastid = "";
+       $activities = json_decode($result);
 
-foreach($activities->items as $item) {
-       if ($item->id == $state["lastid"])
-               break;
+       $initiallastdate = get_pconfig($uid,'fromgplus','lastdate');
 
-       if ($lastid == "")
-               $lastid = $item->id;
+       $lastdate = 0;
 
-       switch($item->object->objectType) {
-               case "note":
-                       $post = html2bbcode($item->object->content);
+       if (!is_array($activities->items))
+               return;
 
-                       if (is_array($item->object->attachments))
-                               $post .= handleattachments($item);
-                       friendicapost($post);
-                       break;
+       $reversed = array_reverse($activities->items);
 
-               case "activity":
-                       $post = html2bbcode($item->annotation)."\n";
-                       //$post .= html2bbcode("&#x2672; ");
-                       $post .= html2bbcode("&#x267B; ");
-                       $post .= "[url=".$item->object->actor->url."]".$item->object->actor->displayName."[/url]";
-                       $post .= " \n";
-                       //$post .= "[quote]";
+       foreach($reversed as $item) {
+               if (strtotime($item->published) <= $initiallastdate)
+                       continue;
 
-                       $post .= html2bbcode($item->object->content);
+               if ($lastdate < strtotime($item->published))
+                       $lastdate = strtotime($item->published);
 
-                       if (is_array($item->object->attachments))
-                               $post .= "\n".trim(handleattachments($item));
+               if ($item->access->description == "Public")
+                       switch($item->object->objectType) {
+                               case "note":
+                                       $post = fromgplus_html2bbcode($item->object->content);
 
-                       //$post .= "[/quote]";
+                                       if (is_array($item->object->attachments))
+                                               $post .= fromgplus_handleattachments($item);
 
-                       friendicapost($post);
-                       break;
+                                       // geocode, placeName
+                                       if (isset($item->address))
+                                               $location = $item->address;
+                                       else
+                                               $location = "";
 
-               default:
-                       print_r($item);
-                       die();
-                       break;
+                                       fromgplus_post($a, $uid, $item->provider->title, $post, $location);
+
+                                       break;
+
+                               case "activity":
+                                       $post = fromgplus_html2bbcode($item->annotation)."\n";
+
+                                       if (intval(get_config('system','new_share'))) {
+                                               $post .= "[share author='".str_replace("'", "&#039;",$item->object->actor->displayName).
+                                                               "' profile='".$item->object->actor->url.
+                                                               "' avatar='".$item->object->actor->image->url.
+                                                               "' link='".$item->object->url."']";
+
+                                               $post .= fromgplus_html2bbcode($item->object->content);
+
+                                               if (is_array($item->object->attachments))
+                                                       $post .= "\n".trim(fromgplus_handleattachments($item));
+
+                                               $post .= "[/share]";
+                                       } else {
+                                               $post .= fromgplus_html2bbcode("&#x2672;");
+                                               $post .= " [url=".$item->object->actor->url."]".$item->object->actor->displayName."[/url] \n";
+                                               $post .= fromgplus_html2bbcode($item->object->content);
+
+                                               if (is_array($item->object->attachments))
+                                                       $post .= "\n".trim(fromgplus_handleattachments($item));
+                                       }
+
+                                       if (isset($item->address))
+                                               $location = $item->address;
+                                       else
+                                               $location = "";
+
+                                       fromgplus_post($a, $uid, $item->provider->title, $post, $location);
+                                       break;
+                       }
        }
+       if ($lastdate != 0)
+               set_pconfig($uid,'fromgplus','lastdate', $lastdate);
 }
 
-if ($lastid != "") {
-       $state['lastid'] = $lastid;
-       file_put_contents($statefile, serialize($state));
+/*
+// Test
+require_once("boot.php");
+
+if(@is_null($a)) {
+        $a = new App;
 }
+
+if(@is_null($db)) {
+        @include(".htconfig.php");
+        require_once("include/dba.php");
+        $db = new dba($db_host, $db_user, $db_pass, $db_data);
+        unset($db_host, $db_user, $db_pass, $db_data);
+};
+
+$test = array();
+fromgplus_cron($a, $test);
 */
index 952a7602f722dc1026904e5dc6598edbedf37a2a..68b7886143b52acd058c34bf12da009f94f39977 100644 (file)
Binary files a/geonames.tgz and b/geonames.tgz differ
index 8226fc0bf6701170ac6518bd94cf185d2a4bfeb3..19725bef3ff53e1561f236cead784715fe8e9757 100755 (executable)
@@ -40,8 +40,8 @@ function geonames_install() {
         *
         */
 
-       register_hook('plugin_settings', 'addon/geonames/geonames.php', 'geonames_settings');
-       register_hook('plugin_settings_post', 'addon/geonames/geonames.php', 'geonames_settings_post');
+       register_hook('plugin_settings', 'addon/geonames/geonames.php', 'geonames_plugin_admin');
+       register_hook('plugin_settings_post', 'addon/geonames/geonames.php', 'geonames_plugin_admin_post');
 
        logger("installed geonames");
 }
@@ -58,8 +58,8 @@ function geonames_uninstall() {
         */
 
        unregister_hook('post_local',    'addon/geonames/geonames.php', 'geonames_post_hook');
-       unregister_hook('plugin_settings', 'addon/geonames/geonames.php', 'geonames_settings');
-       unregister_hook('plugin_settings_post', 'addon/geonames/geonames.php', 'geonames_settings_post');
+       unregister_hook('plugin_settings', 'addon/geonames/geonames.php', 'geonames_plugin_admin');
+       unregister_hook('plugin_settings_post', 'addon/geonames/geonames.php', 'geonames_plugin_admin_post');
 
 
        logger("removed geonames");
@@ -135,7 +135,7 @@ function geonames_post_hook($a, &$item) {
  *
  */
 
-function geonames_settings_post($a,$post) {
+function geonames_plugin_admin_post($a,$post) {
        if(! local_user() || (! x($_POST,'geonames-submit')))
                return;
        set_pconfig(local_user(),'geonames','enable',intval($_POST['geonames']));
@@ -153,7 +153,7 @@ function geonames_settings_post($a,$post) {
 
 
 
-function geonames_settings(&$a,&$s) {
+function geonames_plugin_admin(&$a,&$s) {
 
        if(! local_user())
                return;
index 25106f2658a5c407d184214ee68f1aa089ad7ae5..561c4aaecc00a7c3a8518f328814358b2e513f88 100644 (file)
Binary files a/gravatar.tgz and b/gravatar.tgz differ
diff --git a/gravatar/admin.tpl b/gravatar/admin.tpl
deleted file mode 100644 (file)
index 83144e4..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-{{ inc field_select.tpl with $field=$default_avatar}}{{ endinc }}
-{{ inc field_select.tpl with $field=$rating }}{{ endinc }}
-<div class="submit"><input type="submit" value="$submit" /></div>
index fc5358eb41673088f87bad781fcbe1cc4420eec1..12a8e44f2932670c17bb5eb536c38d775099122e 100644 (file)
@@ -55,7 +55,7 @@ function gravatar_lookup($a, &$b) {
  * Display admin settings for this addon
  */
 function gravatar_plugin_admin (&$a, &$o) {
-       $t = file_get_contents( dirname(__file__)."/admin.tpl");
+       $t = get_markup_template( "admin.tpl", "addon/gravatar/" );
 
        $default_avatar = get_config('gravatar', 'default_img');
        $rating = get_config('gravatar', 'rating');
diff --git a/gravatar/view/admin.tpl b/gravatar/view/admin.tpl
new file mode 100644 (file)
index 0000000..83144e4
--- /dev/null
@@ -0,0 +1,3 @@
+{{ inc field_select.tpl with $field=$default_avatar}}{{ endinc }}
+{{ inc field_select.tpl with $field=$rating }}{{ endinc }}
+<div class="submit"><input type="submit" value="$submit" /></div>
diff --git a/gravatar/view/smarty3/admin.tpl b/gravatar/view/smarty3/admin.tpl
new file mode 100644 (file)
index 0000000..5dfd448
--- /dev/null
@@ -0,0 +1,3 @@
+{{include file="field_select.tpl" field=$default_avatar}}
+{{include file="field_select.tpl" field=$rating}}
+<div class="submit"><input type="submit" value="{{$submit}}" /></div>
diff --git a/group_text.tgz b/group_text.tgz
new file mode 100644 (file)
index 0000000..5dca314
Binary files /dev/null and b/group_text.tgz differ
index 151ff0ae982ed456e2a3b81bc243b181fb1a32eb..5ec5c9c2a97a6096915d439b6e498fe9ed07386e 100755 (executable)
@@ -43,7 +43,7 @@ function group_text_settings_post($a,$post) {
                return;
        set_pconfig(local_user(),'system','groupedit_image_limit',intval($_POST['group_text']));
 
-       info( t('Editplain settings updated.') . EOL);
+       info( t('Group Text settings updated.') . EOL);
 }
 
 
index d87f17f712fb524ed8467fb51daccf44fd7f3023..b47b625cf743a9c32a4caa45007446970cc45c63 100755 (executable)
Binary files a/impressum.tgz and b/impressum.tgz differ
diff --git a/impressum/admin.tpl b/impressum/admin.tpl
deleted file mode 100755 (executable)
index 901df73..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-{{ inc field_input.tpl with $field=$owner }}{{ endinc }}
-{{ inc field_input.tpl with $field=$ownerprofile }}{{ endinc }}
-{{ inc field_textarea.tpl with $field=$postal }}{{ endinc }}
-{{ inc field_textarea.tpl with $field=$notes }}{{ endinc }}
-{{ inc field_input.tpl with $field=$email }}{{ endinc }}
-{{ inc field_textarea.tpl with $field=$footer_text }}{{ endinc }}
-<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
index 9d038178beb8eca2ccf65011481e48702c5b559e..3c1106c9a9761cf056ae63258c871ccafbdb9cc7 100755 (executable)
@@ -78,7 +78,7 @@ function impressum_plugin_admin_post (&$a) {
     info( t('Settings updated.'). EOL );
 }
 function impressum_plugin_admin (&$a, &$o) {
-    $t = file_get_contents( dirname(__file__). "/admin.tpl" );
+    $t = get_markup_template( "admin.tpl", "addon/impressum/" );
     $o = replace_macros($t, array(
         '$submit' => t('Submit'),
         '$owner' => array('owner', t('Site Owner'), get_config('impressum','owner'), t('The page operators name.')),
diff --git a/impressum/view/admin.tpl b/impressum/view/admin.tpl
new file mode 100644 (file)
index 0000000..901df73
--- /dev/null
@@ -0,0 +1,7 @@
+{{ inc field_input.tpl with $field=$owner }}{{ endinc }}
+{{ inc field_input.tpl with $field=$ownerprofile }}{{ endinc }}
+{{ inc field_textarea.tpl with $field=$postal }}{{ endinc }}
+{{ inc field_textarea.tpl with $field=$notes }}{{ endinc }}
+{{ inc field_input.tpl with $field=$email }}{{ endinc }}
+{{ inc field_textarea.tpl with $field=$footer_text }}{{ endinc }}
+<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
diff --git a/impressum/view/smarty3/admin.tpl b/impressum/view/smarty3/admin.tpl
new file mode 100644 (file)
index 0000000..80b6782
--- /dev/null
@@ -0,0 +1,7 @@
+{{include file="field_input.tpl" field=$owner}}
+{{include file="field_input.tpl" field=$ownerprofile}}
+{{include file="field_textarea.tpl" field=$postal}}
+{{include file="field_textarea.tpl" field=$notes}}
+{{include file="field_input.tpl" field=$email}}
+{{include file="field_textarea.tpl" field=$footer_text}}
+<div class="submit"><input type="submit" name="page_site" value="{{$submit}}" /></div>
index 212bb25e62e6ff3f3c8e3a1adab670901b745776..56d6dfa185678e91cd5ff7d33390c19a36b4e508 100644 (file)
Binary files a/jappixmini.tgz and b/jappixmini.tgz differ
index 7b684103edd5afa5b341018970abf6b66be1757f..5a415de7dd170a11604772490a0402aabc88a9ac 100755 (executable)
Binary files a/js_upload.tgz and b/js_upload.tgz differ
index 3ba5f9c4dc74a850d5082565a4df5d09be979972..148fde313a43557d9b2068aa773c029127731590 100755 (executable)
@@ -196,7 +196,13 @@ class qqUploadedFileXhr {
      */
     function save() {    
         $input = fopen("php://input", "r");
-        $this->pathnm = tempnam(sys_get_temp_dir(),'frn');
+
+               $upload_dir = get_config('system','tempdir');
+               if(! $upload_dir)
+                       $upload_dir = sys_get_temp_dir();
+
+        $this->pathnm = tempnam($upload_dir,'frn');
+
                $temp = fopen($this->pathnm,"w");
         $realSize = stream_copy_to_stream($input, $temp);
 
index 0405af9bd532c8ec17112fcbbd3b92d65f07ead8..d61f63bafb394b797b18708f861695ff5cd5af27 100644 (file)
Binary files a/libravatar.tgz and b/libravatar.tgz differ
diff --git a/libravatar/admin.tpl b/libravatar/admin.tpl
deleted file mode 100644 (file)
index 814f4a4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-{{ inc field_select.tpl with $field=$default_avatar}}{{ endinc }}
-<div class="submit"><input type="submit" value="$submit" /></div>
index 08ed6d00b21302d99a0df51920b3e3ff831dedbc..8cbf1e980a611fae3332c58bb127072e7f93350d 100644 (file)
@@ -60,7 +60,7 @@ function libravatar_lookup($a, &$b) {
  * Display admin settings for this addon
  */
 function libravatar_plugin_admin (&$a, &$o) {
-       $t = file_get_contents( dirname(__file__)."/admin.tpl");
+       $t = get_markup_template( "admin.tpl", "addon/libravatar" );
 
        $default_avatar = get_config('libravatar', 'default_img');
 
diff --git a/libravatar/view/admin.tpl b/libravatar/view/admin.tpl
new file mode 100644 (file)
index 0000000..814f4a4
--- /dev/null
@@ -0,0 +1,2 @@
+{{ inc field_select.tpl with $field=$default_avatar}}{{ endinc }}
+<div class="submit"><input type="submit" value="$submit" /></div>
diff --git a/libravatar/view/smarty3/admin.tpl b/libravatar/view/smarty3/admin.tpl
new file mode 100644 (file)
index 0000000..ee95828
--- /dev/null
@@ -0,0 +1,2 @@
+{{include file="field_select.tpl" field=$default_avatar}}
+<div class="submit"><input type="submit" value="{{$submit}}" /></div>
index 840e2ee2abc6ac2551fb6bfc32c22df70578ee2a..db0165854e3f82c97e2379702418cf5c66a76c1d 100644 (file)
Binary files a/ljpost.tgz and b/ljpost.tgz differ
index 2087d3f057a0a241c482268f9aab0d25a0aab6a8..e0494c5c45599d7e32803ec45d5c771044677e17 100755 (executable)
@@ -1,6 +1,5 @@
 
 #ljpost-enable-label, #ljpost-username-label, #ljpost-password-label, #ljpost-bydefault-label {
-<<<<<<< HEAD
        float: left;
        width: 200px;
        margin-top: 10px;
        margin-top: 15px;
 }
 
-=======
-float: left;
-width: 200px;
-margin-top: 10px;
-}
-
-#ljpost-checkbox, #ljpost-username, #ljpost-password, #ljpost-bydefault {
-float: left;
-margin-top: 10px;
-}
-
-#ljpost-submit {
-margin-top: 15px;
-}
->>>>>>> 99d9fddb6af9e872266666038447771e42ce13b4
diff --git a/mahjongg.tar b/mahjongg.tar
new file mode 100644 (file)
index 0000000..56d7051
Binary files /dev/null and b/mahjongg.tar differ
diff --git a/mahjongg/mahjongg.php b/mahjongg/mahjongg.php
new file mode 100755 (executable)
index 0000000..977c693
--- /dev/null
@@ -0,0 +1,42 @@
+<?php\r
+\r
+/**\r
+ * Name: Mah Jongg\r
+ * Description: Ancient Chinese puzzle game that never gets old.\r
+ * Version: 1.0\r
+ * Author: Holger Froese\r
+ */\r
+\r
+\r
+function mahjongg_install() {\r
+    register_hook('app_menu', 'addon/mahjongg/mahjongg.php', 'mahjongg_app_menu');\r
+}\r
+\r
+function mahjongg_uninstall() {\r
+    unregister_hook('app_menu', 'addon/mahjongg/mahjongg.php', 'mahjongg_app_menu');\r
+\r
+}\r
+\r
+function mahjongg_app_menu($a,&$b) {\r
+    $b['app_menu'][] = '<div class="app-title"><a href="mahjongg">Mahjongg</a></div>';\r
+}\r
+\r
+\r
+function mahjongg_module() {}\r
+\r
+function mahjongg_content(&$a) {\r
+\r
+$baseurl = $a->get_baseurl() . '/addon/mahjongg';\r
+\r
+$o .= <<< EOT\r
+<br><br>\r
+<p align="left">\r
+<embed src="addon/mahjongg/mahjongg.swf" quality="high" bgcolor="#FFFFFF" width="800" height="600" name="mahjongg" align="middle" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />\r
+<br><br>\r
+<b>Simply locate the matching tiles and find a way to clear them from the board as quickly as possible.\r
+A timer at the top of the screen keeps track of how you are doing.</b><br>\r
+</p>\r
+EOT;\r
+\r
+return $o;\r
+}\r
diff --git a/mahjongg/mahjongg.swf b/mahjongg/mahjongg.swf
new file mode 100755 (executable)
index 0000000..79f8c9e
Binary files /dev/null and b/mahjongg/mahjongg.swf differ
index bb591e1d30794854f624f4c3649685ddebb711ea..a340aee4799954fc0fb5c9e128f91dd868b14700 100644 (file)
Binary files a/mathjax.tgz and b/mathjax.tgz differ
diff --git a/mathjax/admin.tpl b/mathjax/admin.tpl
deleted file mode 100644 (file)
index 1c723cd..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-{{ inc field_input.tpl with $field=$baseurl }}{{endinc }}
-<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
index 7105772ba80fe1120776c422305949186dbae118..e57d69bf54f6db84fdbca972622c4d319aea31d2 100644 (file)
@@ -66,11 +66,12 @@ function mathjax_plugin_admin_post (&$a) {
     info( t('Settings updated.'). EOL);
 }
 function mathjax_plugin_admin (&$a, &$o) {
-       $t = file_get_contents( dirname(__file__)."/admin.tpl");
-        if (get_config('mathjax','baseurl','') == '') {
-            set_config('mathjax','baseurl','http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML');
-        }
-        $o = replace_macros( $t, array(
+       $t = get_markup_template( "admin.tpl", "addon/mathjax/" );
+       if (get_config('mathjax','baseurl','') == '') {
+               set_config('mathjax','baseurl','http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML');
+       }
+
+       $o = replace_macros( $t, array(
                '$baseurl' => array('baseurl', t('MathJax Base URL'), get_config('mathjax','baseurl' ), t('The URL for the javascript file that should be included to use MathJax. Can be either the MathJax CDN or another installation of MathJax.')),
-            ));
+       ));
 }
diff --git a/mathjax/view/admin.tpl b/mathjax/view/admin.tpl
new file mode 100644 (file)
index 0000000..1c723cd
--- /dev/null
@@ -0,0 +1,2 @@
+{{ inc field_input.tpl with $field=$baseurl }}{{endinc }}
+<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
diff --git a/mathjax/view/smarty3/admin.tpl b/mathjax/view/smarty3/admin.tpl
new file mode 100644 (file)
index 0000000..f6ec03e
--- /dev/null
@@ -0,0 +1,2 @@
+{{include file="field_input.tpl" field=$baseurl}}
+<div class="submit"><input type="submit" name="page_site" value="{{$submit}}" /></div>
diff --git a/morepokes.tgz b/morepokes.tgz
new file mode 100644 (file)
index 0000000..7999b71
Binary files /dev/null and b/morepokes.tgz differ
index bdbd7dcf3c3b019f2d63f3b31424adc660d9ac94..717643ec11f2366e50c1eb9317177948aac3939d 100644 (file)
@@ -19,9 +19,8 @@ function morepokes_poke_verbs($a,&$b) {
        $b['bitchslap'] = array('bitchslapped', t('bitchslap'), t('bitchslapped'));
        $b['shag'] = array('shag', t('shag'), t('shagged'));
        $b['somethingobscenelybiological'] = array('something obscenely biological', t('do something obscenely biological to'), t('did something obscenely biological to'));
-       $b['newpokefeature'] = array('pointed out the new poke feature to', t('point out the new poke feature to'), t('pointed out the new poke feature to'));
+       $b['newpokefeature'] = array('pointed out the poke feature to', t('point out the poke feature to'), t('pointed out the poke feature to'));
        $b['declareundyinglove'] = array('declared undying love for', t('declare undying love for'), t('declared undying love for'));
-       $b['setfireto'] = array('set fire to', t('set fire to'), t('set fire to'));
        $b['patent'] = array('patented', t('patent'), t('patented'));
        $b['strokebeard'] = array('stroked their beard at', t('stroke beard'), t('stroked their beard at'));
        $b['bemoan'] = array('bemoaned the declining standards of modern secondary and tertiary education to', t('bemoan the declining standards of modern secondary and tertiary education to'), t('bemoans the declining standards of modern secondary and tertiary education to'));
@@ -35,4 +34,4 @@ function morepokes_poke_verbs($a,&$b) {
        $b['giggleandfawn'] = array('giggled and fawned at', t('giggle and fawn at'), t('giggled and fawned at'));
        $b['doubt'] = array('doubted', t('doubt'), t('doubted'));
        $b['glare'] = array('glared at', t('glare'), t('glared at'));
-;}
\ No newline at end of file
+;}
index 73870dc3f95647424b8b69a1b7b52eeb276cfd0a..a35ec568c11d4cc7dd0ddac92eee396650de8457 100755 (executable)
Binary files a/nsfw.tgz and b/nsfw.tgz differ
index 60ab458139eb8583a5ca0247fb5e36f03453d993..96e1a9bf8fcc312b396968e3cc106bb857abc720 100755 (executable)
@@ -24,6 +24,37 @@ function nsfw_uninstall() {
 
 }
 
+// This function isn't perfect and isn't trying to preserve the html structure - it's just a 
+// quick and dirty filter to pull out embedded photo blobs because 'nsfw' seems to come up 
+// inside them quite often. We don't need anything fancy, just pull out the data blob so we can
+// check against the rest of the body. 
+function nsfw_extract_photos($body) {
+
+       $new_body = '';
+       
+       $img_start = strpos($body,'src="data:');
+       $img_end = (($img_start !== false) ? strpos(substr($body,$img_start),'>') : false);
+
+       $cnt = 0;
+
+       while($img_end !== false) {
+               $img_end += $img_start;
+               $new_body = $new_body . substr($body,0,$img_start);
+       
+               $cnt ++;
+               $body = substr($body,0,$img_end);
+
+               $img_start = strpos($body,'src="data:');
+               $img_end = (($img_start !== false) ? strpos(substr($body,$img_start),'>') : false);
+
+       }
+
+       if(! $cnt)
+               return $body;
+
+       return $new_body;
+}
 
 
 
@@ -77,6 +108,7 @@ function nsfw_addon_settings_post(&$a,&$b) {
 
 function nsfw_prepare_body(&$a,&$b) {
 
+
        $words = null;
        if(get_pconfig(local_user(),'nsfw','disable'))
                return;
@@ -93,19 +125,22 @@ function nsfw_prepare_body(&$a,&$b) {
 
        $found = false;
        if(count($arr)) {
+
+               $body = nsfw_extract_photos($b['html']);
+
                foreach($arr as $word) {
                        $word = trim($word);
                        if(! strlen($word)) {
                                continue;
                        }
                        if(strpos($word,'/') === 0) {
-                               if(preg_match($word,$b['html'])) {
+                               if(preg_match($word,$body)) {
                                        $found = true;
                                        break;
                                }
                        }
                        else {
-                               if(stristr($b['html'],$word)) {
+                               if(stristr($body,$word)) {
                                        $found = true;
                                        break;
                                }
@@ -115,6 +150,7 @@ function nsfw_prepare_body(&$a,&$b) {
                                }
                        } 
                }
+               
        }
        if($found) {
                $rnd = random_string(8);
index 34f4bd6b15ddd900a4859dfd3e6d6587ba6ee03a..562115c7c85443f861ab48731019a58f5f3ab9e4 100644 (file)
Binary files a/openstreetmap.tgz and b/openstreetmap.tgz differ
diff --git a/openstreetmap/admin.tpl b/openstreetmap/admin.tpl
deleted file mode 100644 (file)
index 75db9cd..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-{{ inc field_input.tpl with $field=$tmsserver }}{{ endinc }}
-{{ inc field_input.tpl with $field=$zoom }}{{ endinc }}
-<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
diff --git a/openstreetmap/openstreetmap.js b/openstreetmap/openstreetmap.js
new file mode 100644 (file)
index 0000000..479e769
--- /dev/null
@@ -0,0 +1,41 @@
+var toolserver = 'http://toolserver.org/~kolossos/openlayers/kml-on-ol.php';\r
+var startTag = '<iframe class="osmFrame" style="width: 100%; height: 350px; clear: both;" src="'+ toolserver + '?lang=de&amp;uselang=de&amp;params=';\r
+var endTag = '"></iframe>';\r
+\r
+jQuery(document).ready(function($) {\r
+\r
+       $('.wall-item-content-wrapper').each(function(index) {\r
+               var link = $(this).find('.wall-item-location .OSMMapLink');\r
+               link.toggle(addIframe, removeIframe);\r
+       });\r
+});\r
+\r
+function addIframe(ev) {\r
+       var coordinate = $(ev.target).attr('title');\r
+\r
+       var newTag = startTag + convertCoordinateString(coordinate) + endTag;\r
+       $(ev.target).parents('.wall-item-content-wrapper').append(newTag);\r
+}\r
+\r
+function removeIframe(ev) {\r
+       $(ev.target).parents('.wall-item-content-wrapper').find('iframe').remove();\r
+\r
+}\r
+\r
+function convertCoordinateString(coordinate) {\r
+       var locstring = coordinate.split(' ');\r
+       var northSouth;\r
+       var westEast;\r
+\r
+       if (locstring[0] < 0) {\r
+               northSouth = '_S_';\r
+       }else{\r
+               northSouth = '_N_';\r
+       }\r
+       if (locstring[1] < 0) {\r
+               westEast = '_W';\r
+       }else{\r
+               westEast = '_E';\r
+       }\r
+       return Math.abs(locstring[0]) + northSouth + Math.abs(locstring[1]) + westEast;\r
+}
\ No newline at end of file
index fda29905d411821fb145ce80aae1c01767731ced..2c5975ebd82a5ab11d72d9482d80f5faf7479bd2 100755 (executable)
 
 function openstreetmap_install() {
        register_hook('render_location', 'addon/openstreetmap/openstreetmap.php', 'openstreetmap_location');
+       register_hook('page_header', 'addon/openstreetmap/openstreetmap.php', 'openstreetmap_alterheader');\r
 
        logger("installed openstreetmap");
 }
 
 function openstreetmap_uninstall() {
        unregister_hook('render_location', 'addon/openstreetmap/openstreetmap.php', 'openstreetmap_location');
+       unregister_hook('page_header', 'addon/openstreetmap/openstreetmap.php', 'openstreetmap_alterheader');
 
        logger("removed openstreetmap");
 }
 
+function openstreetmap_alterheader($a, &$navHtml) {
+       $addScriptTag='<script type="text/javascript" src="' . $a->get_baseurl() . '/addon/openstreetmap/openstreetmap.js' . '"></script>' . "\r\n";\r
+       $a->page['htmlhead'] .= $addScriptTag;
+}
 
 function openstreetmap_location($a, &$item) {
+
+       //
+
        if(! (strlen($item['location']) || strlen($item['coord'])))
-               return; 
+               return;
 
        /*
         * Get the configuration variables from the .htconfig file.
-        */
+       */
        $tmsserver = get_config('openstreetmap','tmsserver');
        if(! $tmsserver)
                $tmsserver = 'http://openstreetmap.org';
@@ -38,12 +47,27 @@ function openstreetmap_location($a, &$item) {
        $location = '';
        $coord = '';
 
+       
+       if($item['location'] && !$item['coord'] && true){ //if only a location is given, find the lat-lon
+               $geo_account='demo';
+\r
+               $s = fetch_url('http://api.geonames.org/search?maxRows=1&fuzzy=0.8&q=' . $item['location']  . '&username=' . $geo_account);\r
+\r
+               if($s){\r
+                       $xml = parse_xml_string($s);\r
+\r
+                       if($xml->geoname->lat && $xml->geoname->lng){\r
+                               $item['coord'] = $xml->geoname->lat . ' ' . $xml->geoname->lng;
+                       }\r
+               }
+       }
+
        $location = (($item['location']) ? '<a target="map" title="' . $item['location'] . '" href="'.$tmsserver.'?q=' . urlencode($item['location']) . '">' . $item['location'] . '</a>' : '');
 
        if($item['coord']) {
                $coords = explode(' ', $item['coord']);
                if(count($coords) > 1) {
-                       $coord = '<a target="map" title="' . $item['coord'] . '" href="'.$tmsserver.'?lat=' . urlencode($coords[0]) . '&lon=' . urlencode($coords[1]) . '&zoom='.$zoom.'">' . $item['coord'] . '</a>' ;
+                       $coord = '<a target="map" class="OSMMapLink" title="' . $item['coord'] . '" href="'.$tmsserver.'?lat=' . urlencode($coords[0]) . '&lon=' . urlencode($coords[1]) . '&zoom='.$zoom.'"> Map </a>' ;
                }
        }
        if(strlen($coord)) {
@@ -58,7 +82,7 @@ function openstreetmap_location($a, &$item) {
 
 
 function openstreetmap_plugin_admin (&$a, &$o) {
-       $t = file_get_contents( dirname(__file__)."/admin.tpl");
+       $t = get_markup_template( "admin.tpl", "addon/openstreetmap/" );
        $tmsserver = get_config('openstreetmap','tmsserver');
        if(! $tmsserver)
                $tmsserver = 'http://openstreetmap.org';
@@ -67,9 +91,9 @@ function openstreetmap_plugin_admin (&$a, &$o) {
                $zoom = 17;
 
        $o = replace_macros( $t, array(
-               '$submit' => t('Submit'),
-               '$tmsserver' => array('tmsserver', t('Tile Server URL'), $tmsserver, t('A list of <a href="http://wiki.openstreetmap.org/wiki/TMS" target="_blank">public tile servers</a>')),
-               '$zoom' => array('zoom', t('Default zoom'), $zoom, t('The default zoom level. (1:world, 18:highest)')),
+                       '$submit' => t('Submit'),
+                       '$tmsserver' => array('tmsserver', t('Tile Server URL'), $tmsserver, t('A list of <a href="http://wiki.openstreetmap.org/wiki/TMS" target="_blank">public tile servers</a>')),
+                       '$zoom' => array('zoom', t('Default zoom'), $zoom, t('The default zoom level. (1:world, 18:highest)')),
        ));
 }
 function openstreetmap_plugin_admin_post (&$a) {
diff --git a/openstreetmap/view/admin.tpl b/openstreetmap/view/admin.tpl
new file mode 100644 (file)
index 0000000..75db9cd
--- /dev/null
@@ -0,0 +1,3 @@
+{{ inc field_input.tpl with $field=$tmsserver }}{{ endinc }}
+{{ inc field_input.tpl with $field=$zoom }}{{ endinc }}
+<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
diff --git a/openstreetmap/view/smarty3/admin.tpl b/openstreetmap/view/smarty3/admin.tpl
new file mode 100644 (file)
index 0000000..6ee0717
--- /dev/null
@@ -0,0 +1,3 @@
+{{include file="field_input.tpl" field=$tmsserver}}
+{{include file="field_input.tpl" field=$zoom}}
+<div class="submit"><input type="submit" name="page_site" value="{{$submit}}" /></div>
index d300a3e2db7b5004167b96a86077e4e3aea349e0..c9610e28bb66cd2f9578de2e642b5cfc1b7d3bc7 100644 (file)
Binary files a/page.tgz and b/page.tgz differ
index 3f0f0419011f233d83fac97ca4956d674d5f7591..21a83e16d48126d96e061d40136b0c55f3e357c1 100755 (executable)
@@ -1,7 +1,7 @@
 <?php
 /**
  * Name: Page
- * Description: Shows list of subscribed community pages/forums on network sidebar
+ * Description: This addon is now deprecated.  Administrators should switch to forumlist instead.  Developers should also add any functionality to forumlist instead of here.
  * Version: 1.0
  * Author: Mike Macgirvin <mike@macgirvin.com>
  * based on pages plugin by
@@ -38,6 +38,7 @@ function page_getpage($uid,$showhidden = true,$randomise = false) {
 
        $contacts = q("SELECT `id`, `url`, `name`, `micro` FROM `contact`
                        WHERE `network`= 'dfrn' AND `forum` = 1 AND `uid` = %d
+                       and blocked = 0 and hidden = 0 and pending = 0 and archive = 0
                        $order ",
                        intval($uid)
        );
index 080dd9e32c6bfd1513b54dcd98fa04ace138b5ed..a5bd437aa4c566a3518df99c19aad2141aadd904 100755 (executable)
Binary files a/piwik.tgz and b/piwik.tgz differ
diff --git a/piwik/admin.tpl b/piwik/admin.tpl
deleted file mode 100755 (executable)
index e57758a..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-{{ inc field_input.tpl with $field=$baseurl }}{{ endinc }}
-{{ inc field_input.tpl with $field=$siteid }}{{ endinc }}
-{{ inc field_checkbox.tpl with $field=$optout }}{{ endinc }}
-{{ inc field_checkbox.tpl with $field=$async }}{{ endinc }}
-<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
index 9ba15db63f9e7dd35445f8cae10d3ef2daad8038..3501b2c8c7a040df36776ed4f21dab4b0460d154 100755 (executable)
@@ -84,7 +84,7 @@ function piwik_analytics($a,&$b) {
        }
 }
 function piwik_plugin_admin (&$a, &$o) {
-       $t = file_get_contents( dirname(__file__)."/admin.tpl");
+       $t = get_markup_template( "admin.tpl", "addon/piwik/" );
        $o = replace_macros( $t, array(
                '$submit' => t('Submit'),
                '$baseurl' => array('baseurl', t('Piwik Base URL'), get_config('piwik','baseurl' ), t('Absolute path to your Piwik installation. (without protocol (http/s), with trailing slash)')),
diff --git a/piwik/view/admin.tpl b/piwik/view/admin.tpl
new file mode 100644 (file)
index 0000000..e57758a
--- /dev/null
@@ -0,0 +1,5 @@
+{{ inc field_input.tpl with $field=$baseurl }}{{ endinc }}
+{{ inc field_input.tpl with $field=$siteid }}{{ endinc }}
+{{ inc field_checkbox.tpl with $field=$optout }}{{ endinc }}
+{{ inc field_checkbox.tpl with $field=$async }}{{ endinc }}
+<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
diff --git a/piwik/view/smarty3/admin.tpl b/piwik/view/smarty3/admin.tpl
new file mode 100644 (file)
index 0000000..bfe04aa
--- /dev/null
@@ -0,0 +1,5 @@
+{{include file="field_input.tpl" field=$baseurl}}
+{{include file="field_input.tpl" field=$siteid}}
+{{include file="field_checkbox.tpl" field=$optout}}
+{{include file="field_checkbox.tpl" field=$async}}
+<div class="submit"><input type="submit" name="page_site" value="{{$submit}}" /></div>
diff --git a/pledgie/pledgie.php b/pledgie/pledgie.php
new file mode 100644 (file)
index 0000000..8f6228f
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+/**
+ *  * Name: Pledgie
+ *   * Description: Show link to Friendica pledgie account for donating
+ *    * Version: 1.0
+ *     * Author: tony baldwin <tony@free-haven.org>
+ *      */
+
+
+function pledgie_install() { register_hook('page_end', 'addon/pledgie/pledgie.php', 'pledgie_active'); }
+
+
+function pledgie_uninstall() { unregister_hook('page_end', 'addon/pledgie/pledgie.php', 'pledgie_active'); }
+
+function pledgie_active(&$a,&$b) { $b .= '<div style="position: fixed; bottom: 25px; left: 5px;"><a href=\'http://www.pledgie.com/campaigns/18417\'><img alt=\'Click here to lend your support to: Beyond Social Networking and make a donation at www.pledgie.com !\' src=\'http://www.pledgie.com/campaigns/18417.png?skin_name=chrome\' border=\'0\' target=\'_blank\' /></a></div>'; } 
+
index b4c100804d3eac95cc71393cd27162f5ba8361c0..45444a683932dcf4da5a6c8ee63fee86b5f868f2 100644 (file)
Binary files a/privacy_image_cache.tgz and b/privacy_image_cache.tgz differ
index f4ada61e1db4ca2684530fd5fd4269d74e73e17a..b0909e814e6791e2a32aea5b8873ce9af778a2e8 100644 (file)
@@ -9,6 +9,7 @@
 define("PRIVACY_IMAGE_CACHE_DEFAULT_TIME", 86400); // 1 Day
 
 require_once('include/security.php');
+require_once("include/Photo.php");
 
 function privacy_image_cache_install() {
     register_hook('prepare_body', 'addon/privacy_image_cache/privacy_image_cache.php', 'privacy_image_cache_prepare_body_hook');
@@ -30,48 +31,85 @@ function privacy_image_cache_uninstall() {
 
 function privacy_image_cache_module() {}
 
-
 function privacy_image_cache_init() {
-       global $a;
-
-       if ($a->config["system"]["db_log"] != "")
-               $stamp1 = microtime(true);
+       global $a, $_SERVER;
+
+       if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
+               header('HTTP/1.1 304 Not Modified');
+               header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT");
+               header('Etag: '.$_SERVER['HTTP_IF_NONE_MATCH']);
+               header("Expires: " . gmdate("D, d M Y H:i:s", time() + (31536000)) . " GMT");
+               header("Cache-Control: max-age=31536000");
+               if(function_exists('header_remove')) {
+                       header_remove('Last-Modified');
+                       header_remove('Expires');
+                       header_remove('Cache-Control');
+               }
+               exit;
+       }
 
        if(function_exists('header_remove')) {
                header_remove('Pragma');
                header_remove('pragma');
        }
 
+       $thumb = false;
+
+       // Look for filename in the arguments
+       if (isset($a->argv[1]) OR isset($a->argv[2]) OR isset($a->argv[3])) {
+               if (isset($a->argv[3]))
+                       $url = $a->argv[3];
+               elseif (isset($a->argv[2]))
+                       $url = $a->argv[2];
+               else
+                       $url = $a->argv[1];
+
+               $pos = strrpos($url, "=.");
+               if ($pos)
+                       $url = substr($url, 0, $pos+1);
+
+               $url = str_replace(array(".jpg", ".jpeg", ".gif", ".png"), array("","","",""), $url);
+
+               $url = base64_decode(strtr($url, '-_', '+/'), true);
+
+               if ($url)
+                       $_REQUEST['url'] = $url;
+               $thumb = (isset($a->argv[3]) and ($a->argv[3] == "thumb"));
+       }
+
        $urlhash = 'pic:' . sha1($_REQUEST['url']);
        // Double encoded url - happens with Diaspora
        $urlhash2 = 'pic:' . sha1(urldecode($_REQUEST['url']));
 
-       $cache = get_config('system','itemcache');
-       if (($cache != '') and is_dir($cache)) {
-               $cachefile = $cache."/".hash("md5", $_REQUEST['url']);
+       $cachefile = get_cachefile(hash("md5", $_REQUEST['url']));
+       if ($cachefile != '') {
                if (file_exists($cachefile)) {
                        $img_str = file_get_contents($cachefile);
-
                        $mime = image_type_to_mime_type(exif_imagetype($cachefile));
 
                        header("Content-type: $mime");
-                       header("Expires: " . gmdate("D, d M Y H:i:s", time() + (3600*24)) . " GMT");
-                       header("Cache-Control: max-age=" . (3600*24));
+                       header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT");
+                       header('Etag: "'.md5($img_str).'"');
+                       header("Expires: " . gmdate("D, d M Y H:i:s", time() + (31536000)) . " GMT");
+                       header("Cache-Control: max-age=31536000");
+
+                       // reduce quality - if it isn't a GIF
+                       if ($mime != "image/gif") {
+                               $img = new Photo($img_str, $mime);
+                               if($img->is_valid())
+                                       $img_str = $img->imageString();
+                       }
 
                        echo $img_str;
 
-                       if ($a->config["system"]["db_log"] != "") {
-                               $stamp2 = microtime(true);
-                               $duration = round($stamp2-$stamp1, 3);
-                               if ($duration > $a->config["system"]["db_loglimit"])
-                                       @file_put_contents($a->config["system"]["db_log"], $duration."\t".strlen($img_str)."\t".$_REQUEST['url']."\n", FILE_APPEND);
-                       }
+                       if (is_dir($_SERVER["DOCUMENT_ROOT"]."/privacy_image_cache"))
+                               file_put_contents($_SERVER["DOCUMENT_ROOT"]."/privacy_image_cache/".privacy_image_cache_cachename($_REQUEST['url'], true), $img_str);
 
                        killme();
                }
        }
 
-       require_once("Photo.php");
+       $valid = true;
 
        $r = q("SELECT * FROM `photo` WHERE `resource-id` in ('%s', '%s') LIMIT 1", $urlhash, $urlhash2);
        if (count($r)) {
@@ -79,21 +117,14 @@ function privacy_image_cache_init() {
                $mime = $r[0]["desc"];
                if ($mime == "") $mime = "image/jpeg";
 
-               // Test
-               //if ($mime == "image/jpeg") {
-               //      $img = new Photo($img_str);
-               //      if($img->is_valid()) {
-               //              $img->scaleImage(1000);
-               //              $img_str = $img->imageString();
-               //      }
-               //}
        } else {
                // It shouldn't happen but it does - spaces in URL
                $_REQUEST['url'] = str_replace(" ", "+", $_REQUEST['url']);
 
-               $img_str = fetch_url($_REQUEST['url'],true);
+               $redirects = 0;
+               $img_str = fetch_url($_REQUEST['url'],true, $redirects, 10);
 
-               $tempfile = tempnam("", "cache");
+               $tempfile = tempnam(get_config("system","temppath"), "cache");
                file_put_contents($tempfile, $img_str);
                $mime = image_type_to_mime_type(exif_imagetype($tempfile));
                unlink($tempfile);
@@ -102,7 +133,13 @@ function privacy_image_cache_init() {
                if ((substr($a->get_curl_code(), 0, 1) == "4") or (!$img_str)) {
                        $img_str = file_get_contents("images/blank.png");
                        $mime = "image/png";
-               //} else if (substr($img_str, 0, 6) == "GIF89a") {
+                       $cachefile = ""; // Clear the cachefile so that the dummy isn't stored
+                       $valid = false;
+                       $img = new Photo($img_str, "image/png");
+                       if($img->is_valid()) {
+                               $img->scaleImage(10);
+                               $img_str = $img->imageString();
+                       }
                } else if ($mime != "image/jpeg") {
                        $image = @imagecreatefromstring($img_str);
 
@@ -126,34 +163,75 @@ function privacy_image_cache_init() {
                        );
 
                } else {
-                       $img = new Photo($img_str);
+                       $img = new Photo($img_str, $mime);
                        if($img->is_valid()) {
                                $img->store(0, 0, $urlhash, $_REQUEST['url'], '', 100);
-                               //$img->scaleImage(1000); // Test
+                               if ($thumb)
+                                       $img->scaleImage(200); // Test
                                $img_str = $img->imageString();
                        }
-                       $mime = "image/jpeg";
+                       //$mime = "image/jpeg";
                }
        }
+       // reduce quality - if it isn't a GIF
+       if ($mime != "image/gif") {
+               $img = new Photo($img_str, $mime);
+               if($img->is_valid())
+                       $img_str = $img->imageString();
+       }
 
-       // Writing in cachefile
-       if (isset($cachefile) && ($cachefile != '') and (file_exists($cachefile)) and (exif_imagetype($cachefile) > 0))
+       // If there is a real existing directory then put the cache file there
+       // advantage: real file access is really fast
+       // Otherwise write in cachefile
+       if ($valid AND is_dir($_SERVER["DOCUMENT_ROOT"]."/privacy_image_cache"))
+               file_put_contents($_SERVER["DOCUMENT_ROOT"]."/privacy_image_cache/".privacy_image_cache_cachename($_REQUEST['url'], true), $img_str);
+       elseif ($cachefile != '')
                file_put_contents($cachefile, $img_str);
 
        header("Content-type: $mime");
-       header("Expires: " . gmdate("D, d M Y H:i:s", time() + (3600*24)) . " GMT");
-       header("Cache-Control: max-age=" . (3600*24));
+
+       // Only output the cache headers when the file is valid
+       if ($valid) {
+               header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT");
+               header('Etag: "'.md5($img_str).'"');
+               header("Expires: " . gmdate("D, d M Y H:i:s", time() + (31536000)) . " GMT");
+               header("Cache-Control: max-age=31536000");
+       }
 
        echo $img_str;
 
-       if ($a->config["system"]["db_log"] != "") {
-               $stamp2 = microtime(true);
-               $duration = round($stamp2-$stamp1, 3);
-               if ($duration > $a->config["system"]["db_loglimit"])
-                       @file_put_contents($a->config["system"]["db_log"], $duration."\t".strlen($img_str)."\t".$_REQUEST['url']."\n", FILE_APPEND);
+       killme();
+}
+
+function privacy_image_cache_cachename($url, $writemode = false) {
+       global $_SERVER;
+
+       $pos = strrpos($url, ".");
+       if ($pos) {
+               $extension = strtolower(substr($url, $pos+1));
+               $pos = strpos($extension, "?");
+               if ($pos)
+                       $extension = substr($extension, 0, $pos);
        }
 
-       killme();
+       $basepath = $_SERVER["DOCUMENT_ROOT"]."/privacy_image_cache";
+
+       $path = substr(hash("md5", $url), 0, 2);
+
+       if (is_dir($basepath) and $writemode)
+               if (!is_dir($basepath."/".$path)) {
+                       mkdir($basepath."/".$path);
+                       chmod($basepath."/".$path, 0777);
+               }
+
+       $path .= "/".strtr(base64_encode($url), '+/', '-_');
+
+       $extensions = array("jpg", "jpeg", "gif", "png");
+
+       if (in_array($extension, $extensions))
+               $path .= ".".$extension;
+
+       return($path);
 }
 
 /**
@@ -161,13 +239,21 @@ function privacy_image_cache_init() {
  * @return boolean
  */
 function privacy_image_cache_is_local_image($url) {
-    if ($url[0] == '/') return true;
+       if ($url[0] == '/') return true;
+
        if (strtolower(substr($url, 0, 5)) == "data:") return true;
 
+       // Check if the cached path would be longer than 255 characters - apache doesn't like it
+       if (is_dir($_SERVER["DOCUMENT_ROOT"]."/privacy_image_cache")) {
+               $cachedurl = get_app()->get_baseurl()."/privacy_image_cache/". privacy_image_cache_cachename($url);
+               if (strlen($url) > 150)
+                       return true;
+       }
+
        // links normalised - bug #431
-    $baseurl = normalise_link(get_app()->get_baseurl());
+       $baseurl = normalise_link(get_app()->get_baseurl());
        $url = normalise_link($url);
-    return (substr($url, 0, strlen($baseurl)) == $baseurl);
+       return (substr($url, 0, strlen($baseurl)) == $baseurl);
 }
 
 /**
@@ -175,11 +261,23 @@ function privacy_image_cache_is_local_image($url) {
  * @return string
  */
 function privacy_image_cache_img_cb($matches) {
+
+       // if the picture seems to be from another picture cache then take the original source
+       $queryvar = privacy_image_cache_parse_query($matches[2]);
+       if ($queryvar['url'] != "")
+               $matches[2] = urldecode($queryvar['url']);
+
+       // if fetching facebook pictures don't fetch the thumbnail but the big one
+       if (strpos($matches[2], ".fbcdn.net/") and (substr($matches[2], -6) == "_s.jpg"))
+               $matches[2] = substr($matches[2], 0, -6)."_n.jpg";
+
        // following line changed per bug #431
        if (privacy_image_cache_is_local_image($matches[2]))
                return $matches[1] . $matches[2] . $matches[3];
 
-       return $matches[1] . get_app()->get_baseurl() . "/privacy_image_cache/?url=" . addslashes(rawurlencode(htmlspecialchars_decode($matches[2]))) . $matches[3];
+       //return $matches[1] . get_app()->get_baseurl() . "/privacy_image_cache/?url=" . addslashes(rawurlencode(htmlspecialchars_decode($matches[2]))) . $matches[3];
+
+       return $matches[1].get_app()->get_baseurl()."/privacy_image_cache/". privacy_image_cache_cachename(htmlspecialchars_decode($matches[2])).$matches[3];
 }
 
 /**
@@ -207,9 +305,14 @@ function privacy_image_cache_bbcode_hook(&$a, &$o) {
 function privacy_image_cache_display_item_hook(&$a, &$o) {
     if (isset($o["output"])) {
         if (isset($o["output"]["thumb"]) && !privacy_image_cache_is_local_image($o["output"]["thumb"]))
-            $o["output"]["thumb"] = $a->get_baseurl() . "/privacy_image_cache/?url=" . escape_tags(addslashes(rawurlencode($o["output"]["thumb"])));
+            $o["output"]["thumb"] = $a->get_baseurl() . "/privacy_image_cache/".privacy_image_cache_cachename($o["output"]["thumb"]);
+            //$o["output"]["thumb"] = $a->get_baseurl() . "/privacy_image_cache/?url=" . escape_tags(addslashes(rawurlencode($o["output"]["thumb"])));
         if (isset($o["output"]["author-avatar"]) && !privacy_image_cache_is_local_image($o["output"]["author-avatar"]))
-            $o["output"]["author-avatar"] = $a->get_baseurl() . "/privacy_image_cache/?url=" . escape_tags(addslashes(rawurlencode($o["output"]["author-avatar"])));
+            $o["output"]["author-avatar"] = $a->get_baseurl() . "/privacy_image_cache/".privacy_image_cache_cachename($o["output"]["author-avatar"]);
+            //$o["output"]["author-avatar"] = $a->get_baseurl() . "/privacy_image_cache/?url=" . escape_tags(addslashes(rawurlencode($o["output"]["author-avatar"])));
+        if (isset($o["output"]["owner-avatar"]) && !privacy_image_cache_is_local_image($o["output"]["owner-avatar"]))
+            $o["output"]["owner-avatar"] = $a->get_baseurl() . "/privacy_image_cache/".privacy_image_cache_cachename($o["output"]["owner-avatar"]);
+            //$o["output"]["owner-avatar"] = $a->get_baseurl() . "/privacy_image_cache/?url=" . escape_tags(addslashes(rawurlencode($o["output"]["owner-avatar"])));
     }
 }
 
@@ -220,7 +323,8 @@ function privacy_image_cache_display_item_hook(&$a, &$o) {
  */
 function privacy_image_cache_ping_xmlize_hook(&$a, &$o) {
     if ($o["photo"] != "" && !privacy_image_cache_is_local_image($o["photo"]))
-        $o["photo"] = $a->get_baseurl() . "/privacy_image_cache/?url=" . escape_tags(addslashes(rawurlencode($o["photo"])));
+        $o["photo"] = $a->get_baseurl() . "/privacy_image_cache/".privacy_image_cache_cachename($o["photo"]);
+        //$o["photo"] = $a->get_baseurl() . "/privacy_image_cache/?url=" . escape_tags(addslashes(rawurlencode($o["photo"])));
 }
 
 
@@ -238,11 +342,11 @@ function privacy_image_cache_cron(&$a = null, &$b = null) {
 
     logger("Purging old Cache of the Privacy Image Cache", LOGGER_DEBUG);
     q('DELETE FROM `photo` WHERE `uid` = 0 AND `resource-id` LIKE "pic:%%" AND `created` < NOW() - INTERVAL %d SECOND', $cachetime);
-    set_config('pi_cache', 'last_delete', $time);
-}
-
 
+    clear_cache($a->get_basepath(), $a->get_basepath()."/privacy_image_cache");
 
+    set_config('pi_cache', 'last_delete', $time);
+}
 
 /**
  * @param App $a
@@ -289,3 +393,22 @@ function privacy_image_cache_plugin_admin_post(&$a = null, &$o = null){
         q('DELETE FROM `photo` WHERE `uid` = 0 AND `resource-id` LIKE "pic:%%"');
     }
 }
+
+function privacy_image_cache_parse_query($var) {
+       /**
+        *  Use this function to parse out the query array element from
+        *  the output of parse_url().
+       */
+       $var  = parse_url($var, PHP_URL_QUERY);
+       $var  = html_entity_decode($var);
+       $var  = explode('&', $var);
+       $arr  = array();
+
+       foreach($var as $val) {
+               $x          = explode('=', $val);
+               $arr[$x[0]] = $x[1];
+       }
+
+       unset($val, $x, $var);
+       return $arr;
+}
diff --git a/procrunner.tgz b/procrunner.tgz
new file mode 100644 (file)
index 0000000..fec9dfa
Binary files /dev/null and b/procrunner.tgz differ
diff --git a/procrunner/procrunner.php b/procrunner/procrunner.php
new file mode 100755 (executable)
index 0000000..4c6f64b
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Name: Proc Runner
+ * Description: Derivative of poormancron when proc_open() and exec() are disabled
+ * Version: 1.0
+ * Author: Fabio Comuni <http://kirgroup.com/profile/fabrix>
+ * Author: Mike Macgirvin
+ */
+
+function procrunner_install() {
+
+       $addons = get_config('system','addon');
+       if(strstr('poormancron',$addons)) {
+               logger('procrunner incompatible with poormancron. Not installing procrunner.');
+               return;
+       }
+
+       // check for command line php
+       $a = get_app();
+       $ex = Array();
+       $ex[0] = ((x($a->config,'php_path')) && (strlen($a->config['php_path'])) ? $a->config['php_path'] : 'php');
+       $ex[1] = dirname(dirname(dirname(__file__)))."/testargs.php";
+       $ex[2] = "test";
+       $out = exec(implode(" ", $ex));
+       if ($out==="test") {
+               logger('procrunner not required on this system. Not installing.');
+               return;
+       } else {
+               register_hook('proc_run', 'addon/procrunner/procrunner.php','procrunner_procrun');
+               logger("installed procrunner");
+       }
+       
+}
+
+function procrunner_uninstall() {
+       unregister_hook('proc_run', 'addon/procrunner/procrunner.php','procrunner_procrun');
+       logger("removed procrunner");
+}
+
+
+
+function procrunner_procrun(&$a, &$arr) {
+
+       $argv = $arr['args'];
+       $arr['run_cmd'] = false;
+       logger("procrunner procrun ".implode(", ",$argv));
+       array_shift($argv);
+       $argc = count($argv);
+       logger("procrunner procrun require_once ".basename($argv[0]));
+       require_once(basename($argv[0]));
+       $funcname=str_replace(".php", "", basename($argv[0]))."_run";  
+       $funcname($argv, $argc);
+}
index 7ab5f0db9d1769808dd0747f587395e7a32f6b15..bdad8bafb861a0914d5423129024f9cf2949f58e 100755 (executable)
Binary files a/randplace.tgz and b/randplace.tgz differ
diff --git a/remote_permissions.tgz b/remote_permissions.tgz
new file mode 100644 (file)
index 0000000..fef4f39
Binary files /dev/null and b/remote_permissions.tgz differ
diff --git a/remote_permissions/README.md b/remote_permissions/README.md
new file mode 100644 (file)
index 0000000..b9e3858
--- /dev/null
@@ -0,0 +1,8 @@
+The Remote Permissions plugin enables recipients of private posts to see who else has received the post. This can be beneficial on community servers where people may want to modify the way they speak depending on who can see their comments to the post.
+
+Note that since Friendica is federated, the local hub may have posts that originated elsewhere. In that case, the plugin has no way of knowing all the recipients of the post, and it must settle for finding out who else can see it on the local hub.
+
+The hub admin can specify one of two behaviors for this plugin:
+
+* **Global:** every private post on the local hub will show all recipients (or at least the ones it can discover) of the post to any other users on the local hub
+* **Individual:** only private posts from those users on the local hub who "opt-in" will show the post recipients. None of the private posts that originated elsewhere will show even partial lists of post recipients
diff --git a/remote_permissions/remote_permissions.php b/remote_permissions/remote_permissions.php
new file mode 100644 (file)
index 0000000..8955130
--- /dev/null
@@ -0,0 +1,207 @@
+<?php
+/**
+ * Name: Remote Permissions
+ * Description: Allow the recipients of private posts to see who else can see the post by clicking the lock icon
+ * Version: 1.0
+ * Author: Zach <https://f.shmuz.in/profile/techcity>
+ * 
+ */
+
+
+function remote_permissions_install() {
+       register_hook('lockview_content', 'addon/remote_permissions/remote_permissions.php', 'remote_permissions_content');
+       register_hook('plugin_settings', 'addon/remote_permissions/remote_permissions.php', 'remote_permissions_settings');
+       register_hook('plugin_settings_post', 'addon/remote_permissions/remote_permissions.php', 'remote_permissions_settings_post');
+}
+
+function remote_permissions_uninstall() {
+       unregister_hook('lockview_content', 'addon/remote_permissions/remote_permissions.php', 'remote_permissions_content');
+       unregister_hook('plugin_settings', 'addon/remote_permissions/remote_permissions.php', 'remote_permissions_settings');
+       unregister_hook('plugin_settings_post', 'addon/remote_permissions/remote_permissions.php', 'remote_permissions_settings_post');
+}
+
+function remote_permissions_settings(&$a,&$o) {
+
+       if(! local_user())
+               return;
+
+       $global = get_config("remote_perms", "global");
+       if($global == 1)
+               return;
+
+       /* Add our stylesheet to the page so we can make our settings look nice */
+
+       $a->page['htmlhead'] .= '<link rel="stylesheet"  type="text/css" href="' . $a->get_baseurl() . '/addon/remote_permissions/settings.css' . '" media="all" />' . "\r\n";
+
+       /* Get the current state of our config variable */
+
+       $remote_perms = get_pconfig(local_user(),'remote_perms','show');
+       
+       /* Add some HTML to the existing form */
+
+//     $t = file_get_contents("addon/remote_permissions/settings.tpl" );
+       $t = get_markup_template("settings.tpl", "addon/remote_permissions/" );
+       $o .= replace_macros($t, array(
+               '$remote_perms_title' => t('Remote Permissions Settings'),
+               '$remote_perms_label' => t('Allow recipients of your private posts to see the other recipients of the posts'),
+               '$checked' => (($remote_perms == 1) ? 'checked="checked"' : ''),
+               '$submit' => t('Submit')
+       ));
+
+}
+
+function remote_permissions_settings_post($a,$post) {
+       if(! local_user() || (! x($_POST,'remote-perms-submit')))
+               return;
+
+       set_pconfig(local_user(),'remote_perms','show',intval($_POST['remote-perms']));
+       info( t('Remote Permissions settings updated.') . EOL);
+}
+
+function remote_permissions_content($a, $item_copy) {
+
+       if($item_copy['uid'] != local_user())
+               return;
+
+       if(get_config('remote_perms','global') == 0) {
+               // Admin has set Individual choice. We need to find
+               // the original poster. First, get the contact's info
+               $r = q("SELECT nick, url FROM contact WHERE id = %d LIMIT 1",
+                      intval($item_copy['contact-id'])
+               );
+               if(! $r) 
+                       return;
+
+               // Find out if the contact lives here
+               $baseurl = $a->get_baseurl();
+               $baseurl = substr($baseurl, strpos($baseurl, '://') + 3);
+               if(strpos($r[0]['url'], $baseurl) === false)
+                       return;
+
+               // The contact lives here. Get his/her user info
+               $nick = $r[0]['nick'];
+               $r = q("SELECT uid FROM user WHERE nickname = '%s' LIMIT 1",
+                      dbesc($nick)
+               );
+               if(! $r)
+                       return;
+
+               if(get_pconfig($r[0]['uid'],'remote_perms','show') == 0)
+                       return;
+       }
+
+       if(($item_copy['private'] == 1) && (! strlen($item_copy['allow_cid'])) && (! strlen($item_copy['allow_gid']))
+               && (! strlen($item_copy['deny_cid'])) && (! strlen($item_copy['deny_gid']))) {
+
+               $allow_names = array();
+
+               // Check for the original post here -- that's the only way
+               // to definitely get all of the recipients
+
+               if($item_copy['uri'] === $item_copy['parent-uri']) {
+                       // Lockview for a top-level post
+                       $r = q("SELECT allow_cid, allow_gid, deny_cid, deny_gid FROM item WHERE uri = '%s' AND type = 'wall' LIMIT 1",
+                                  dbesc($item_copy['uri'])
+                       );
+               }
+               else {
+                       // Lockview for a comment
+                       $r = q("SELECT allow_cid, allow_gid, deny_cid, deny_gid FROM item WHERE uri = '%s'
+                               AND parent = ( SELECT id FROM item WHERE uri = '%s' AND type = 'wall' ) LIMIT 1",
+                                  dbesc($item_copy['uri']),
+                                  dbesc($item_copy['parent-uri'])
+                       );
+               }
+               if($r) {
+
+                       $item = $r[0];
+
+                       $allowed_users = expand_acl($item['allow_cid']);
+                       $allowed_groups = expand_acl($item['allow_gid']);
+                       $deny_users = expand_acl($item['deny_cid']);
+                       $deny_groups = expand_acl($item['deny_gid']);
+
+                       $o = t('Visible to:') . '<br />';
+                       $allow = array();
+                       $deny = array();
+
+                       if(count($allowed_groups)) {
+                               $r = q("SELECT DISTINCT `contact-id` FROM group_member WHERE gid IN ( %s )",
+                                       dbesc(implode(', ', $allowed_groups))
+                               );
+                               foreach($r as $rr) 
+                                       $allow[] = $rr['contact-id'];
+                       }
+                       $allow = array_unique($allow + $allowed_users);
+
+                       if(count($deny_groups)) {
+                               $r = q("SELECT DISTINCT `contact-id` FROM group_member WHERE gid IN ( %s )",
+                                       dbesc(implode(', ', $deny_groups))
+                               );
+                               foreach($r as $rr) 
+                                       $deny[] = $rr['contact-id'];
+                       }
+                       $deny = $deny + $deny_users;
+
+                       if($allow)
+                       {
+                               $r = q("SELECT name FROM contact WHERE id IN ( %s )",
+                                          dbesc(implode(', ', array_diff($allow, $deny)))
+                               );
+                               foreach($r as $rr)
+                                       $allow_names[] = $rr['name'];
+                       }
+               }
+               else {
+                       // We don't have the original post. Let's try for the next best thing:
+                       // checking who else has the post on our own server. Note that comments
+                       // that were sent to Diaspora and were relayed to others on our server
+                       // will have different URIs than the original. We can match the GUID for
+                       // those
+                       $r = q("SELECT `uid` FROM item WHERE uri = '%s' OR guid = '%s'",
+                                  dbesc($item_copy['uri']),
+                              dbesc($item_copy['guid'])
+                       );
+                       if(! $r)
+                               return;
+
+                       $allow = array();
+                       foreach($r as $rr)
+                               $allow[] = $rr['uid'];
+
+                       $r = q("SELECT username FROM user WHERE uid IN ( %s )",
+                               dbesc(implode(', ', $allow))
+                       );
+                       if(! $r)
+                               return;
+
+                       $o = t('Visible to') . ' (' . t('may only be a partial list') . '):<br />';
+
+                       foreach($r as $rr)
+                               $allow_names[] = $rr['username'];
+               }
+
+               // Sort the names alphabetically, case-insensitive
+               natcasesort($allow_names);
+               echo $o . implode(', ', $allow_names);
+               killme();
+       }
+
+       return;
+}
+
+function remote_permissions_plugin_admin(&$a, &$o){
+       $t = get_markup_template( "admin.tpl", "addon/remote_permissions/" );
+       $o = replace_macros($t, array(
+               '$submit' => t('Submit'),
+               '$global' => array('remotepermschoice', t('Global'), 1, t('The posts of every user on this server show the post recipients'),  get_config('remote_perms', 'global') == 1),
+               '$individual' => array('remotepermschoice', t('Individual'), 2, t('Each user chooses whether his/her posts show the post recipients'),  get_config('remote_perms', 'global') == 0)
+       ));
+}
+
+function remote_permissions_plugin_admin_post(&$a){
+       $choice =       ((x($_POST,'remotepermschoice'))                ? notags(trim($_POST['remotepermschoice']))     : '');
+       set_config('remote_perms','global',($choice == 1 ? 1 : 0));
+       info( t('Settings updated.'). EOL );
+}
+
diff --git a/remote_permissions/settings.css b/remote_permissions/settings.css
new file mode 100644 (file)
index 0000000..ef6051d
--- /dev/null
@@ -0,0 +1,16 @@
+
+
+
+#remote-perms-label {
+       float: left;
+       width: 200px;
+       margin-bottom: 25px;
+       margin-right: 20px;
+       text-align: justify;
+}
+
+#remote-perms {
+       float: left;
+}
+
+
diff --git a/remote_permissions/view/admin.tpl b/remote_permissions/view/admin.tpl
new file mode 100644 (file)
index 0000000..6055880
--- /dev/null
@@ -0,0 +1,3 @@
+{{ inc field_radio.tpl with $field=$global }}{{ endinc }}
+{{ inc field_radio.tpl with $field=$individual }}{{ endinc }}
+<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
diff --git a/remote_permissions/view/settings.tpl b/remote_permissions/view/settings.tpl
new file mode 100644 (file)
index 0000000..9fd9895
--- /dev/null
@@ -0,0 +1,8 @@
+       <div class="settings-block">
+       <h3>$remote_perms_title</h3>
+       <div id="remote-perms-wrapper">
+       <label id="remote-perms-label" for="remote-perms">$remote_perms_label</label>
+       <input id="remote-perms-input" type="checkbox" name="remote-perms" value="1" $checked />
+       </div><div class="clear"></div>
+       <div class="settings-submit-wrapper" ><input type="submit" name="remote-perms-submit" class="settings-submit" value="$submit" /></div></div>
+
diff --git a/remote_permissions/view/smarty3/admin.tpl b/remote_permissions/view/smarty3/admin.tpl
new file mode 100644 (file)
index 0000000..e67afd7
--- /dev/null
@@ -0,0 +1,3 @@
+{{include file="field_radio.tpl" field=$global}}
+{{include file="field_radio.tpl" field=$individual}}
+<div class="submit"><input type="submit" name="page_site" value="{{$submit}}" /></div>
diff --git a/remote_permissions/view/smarty3/settings.tpl b/remote_permissions/view/smarty3/settings.tpl
new file mode 100644 (file)
index 0000000..df89a32
--- /dev/null
@@ -0,0 +1,8 @@
+       <div class="settings-block">
+       <h3>{{$remote_perms_title}}</h3>
+       <div id="remote-perms-wrapper">
+       <label id="remote-perms-label" for="remote-perms">{{$remote_perms_label}}</label>
+       <input id="remote-perms-input" type="checkbox" name="remote-perms" value="1" {{$checked}} />
+       </div><div class="clear"></div>
+       <div class="settings-submit-wrapper" ><input type="submit" name="remote-perms-submit" class="settings-submit" value="{{$submit}}" /></div></div>
+
diff --git a/rendertime/rendertime.php b/rendertime/rendertime.php
new file mode 100755 (executable)
index 0000000..dcbfb41
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+
+
+/**
+ * Name: rendertime
+ * Description: Shows the time that was needed to render the current page
+ * Version: 0.1
+ * Author: Michael Vvogel <http://pirati.ca/profile/heluecht>
+ *
+ */
+
+function rendertime_install() {
+       register_hook('page_end', 'addon/rendertime/rendertime.php', 'rendertime_page_end');
+}
+
+
+function rendertime_uninstall() {
+       unregister_hook('init_1', 'addon/rendertime/rendertime.php', 'rendertime_init_1');
+       unregister_hook('page_end', 'addon/rendertime/rendertime.php', 'rendertime_page_end');
+}
+
+function rendertime_init_1(&$a) {
+}
+
+function rendertime_page_end(&$a, &$o) {
+
+       $duration = microtime(true)-$a->performance["start"];
+
+       $o = $o.'<div class="renderinfo">'.sprintf(t("Performance: Database: %s, Network: %s, Rendering: %s, Parser: %s, I/O: %s, Other: %s, Total: %s"),
+                                               round($a->performance["database"], 3),
+                                               round($a->performance["network"], 3),
+                                               round($a->performance["rendering"], 3),
+                                               round($a->performance["parser"], 3),
+                                               round($a->performance["file"], 3),
+                                               round($duration - $a->performance["database"] - $a->performance["network"]
+                                                        - $a->performance["rendering"] - $a->performance["parser"]
+                                                        - $a->performance["file"], 3),
+                                               round($duration, 3)
+                                               //round($a->performance["markstart"], 3)
+                                               //round($a->performance["plugin"], 3)
+                                               )."</div>";
+
+}
index 8c184414c9e494ce8b0444e99211b90176433e53..2efe63322c73961c2589ca82b927304bf3dc109d 100644 (file)
Binary files a/smiley_pack.tgz and b/smiley_pack.tgz differ
diff --git a/smiley_pack/icons/food/birthdaycake.gif b/smiley_pack/icons/food/birthdaycake.gif
new file mode 100644 (file)
index 0000000..30ebceb
Binary files /dev/null and b/smiley_pack/icons/food/birthdaycake.gif differ
index 4623ded5a667eed08b74d52dc87bc304be4fc875..4d49b7c0275c2b5a74237553a49ebc0f83f47140 100644 (file)
@@ -370,6 +370,9 @@ function smiley_pack_smilies(&$a,&$b) {
        $b['texts'][] = ':fryegg';
        $b['icons'][] = '<img class="smiley" src="' . $a->get_baseurl() . '/addon/smiley_pack/icons/food/fryegg.gif' . '" alt="' . ':fryegg' . '" />';
 
+       $b['texts'][] = ':birthdaycake';
+       $b['icons'][] = '<img class="smiley" src="' . $a->get_baseurl() . '/addon/smiley_pack/icons/food/birthdaycake.gif' . '" alt="' . ':birthdaycake' . '" />';
+
 #Happy smileys
 
        $b['texts'][] = ':cloud9';
index fa75b3e40f426248d299f2e9e3b2b23090eb5ed6..fba75c15bec3d665ebacb7fe7e84c9277a7edd13 100755 (executable)
Binary files a/sniper.tgz and b/sniper.tgz differ
index c171f2c38aa190988fc5792d04fe3fb5b71df60e..da873b1755c8538cc894d8fc54550af7618a568e 100755 (executable)
Binary files a/statusnet.tgz and b/statusnet.tgz differ
diff --git a/statusnet/admin.tpl b/statusnet/admin.tpl
deleted file mode 100755 (executable)
index b40adf3..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-{{ for $sites as $s }}
-       {{ inc field_input.tpl with $field=$s.sitename }}{{ endinc }}
-       {{ inc field_input.tpl with $field=$s.apiurl }}{{ endinc }}
-       {{ inc field_input.tpl with $field=$s.secret }}{{ endinc }}
-       {{ inc field_input.tpl with $field=$s.key }}{{ endinc }}
-       {{ if $s.delete }}
-               {{ inc field_checkbox.tpl with $field=$s.delete }}{{ endinc }}
-               <hr>
-       {{ else }}
-               <p>Fill this form to add a new site</p>
-       {{ endif }}
-       
-{{ endfor }}
-
-
-<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
index a5594cb70249ae183b2de56eafea233de1caf546..81c38d98a1c1a841f72832b6151831b5e843f9e8 100755 (executable)
        width: 250px;
        margin-bottom: 25px;
 }
-#statusnet-default-label {
-       float: left;
-       width: 250px;
-}
-#statusnet-sendtaglinks-label {
-        float: left;
-        width: 250px;
-        margin-bottom: 25px;
-}
 #statusnet-disconnect {
        float: left;
 }
 
+#statusnet-default-label,
+#statusnet-applicationname-label,
+#statusnet-sendtaglinks-label,
+#statusnet-shortening-label, 
+#statusnet-mirror-label,
+#statusnet-pin-label,
 #statusnet-enable-label {
        float: left;
        width: 250px;
        float: left;
 }
 
-#statusnet-pin-label {
-       float: left;
-       width: 250px;
-       margin-bottom: 25px;
-}
 #statusnet-pin {
        float: left;
 }
index 46b3f03f520fa3fab23581da76839430bf54b10b..77bff7a44fe199d7494a43008f490aa7f7639e47 100755 (executable)
@@ -30,6 +30,8 @@
  * Thank you guys for the Twitter compatible API!
  */
 
+define('STATUSNET_DEFAULT_POLL_INTERVAL', 5); // given in minutes
+
 require_once('library/twitteroauth.php');
 
 class StatusNetOAuth extends TwitterOAuth {
@@ -104,6 +106,7 @@ function statusnet_install() {
        register_hook('notifier_normal', 'addon/statusnet/statusnet.php', 'statusnet_post_hook');
        register_hook('post_local', 'addon/statusnet/statusnet.php', 'statusnet_post_local');
        register_hook('jot_networks',    'addon/statusnet/statusnet.php', 'statusnet_jot_nets');
+       register_hook('cron', 'addon/statusnet/statusnet.php', 'statusnet_cron');
        logger("installed statusnet");
 }
 
@@ -114,6 +117,7 @@ function statusnet_uninstall() {
        unregister_hook('notifier_normal', 'addon/statusnet/statusnet.php', 'statusnet_post_hook');
        unregister_hook('post_local', 'addon/statusnet/statusnet.php', 'statusnet_post_local');
        unregister_hook('jot_networks',    'addon/statusnet/statusnet.php', 'statusnet_jot_nets');
+       unregister_hook('cron', 'addon/statusnet/statusnet.php', 'statusnet_cron');
 
        // old setting - remove only
        unregister_hook('post_local_end', 'addon/statusnet/statusnet.php', 'statusnet_post_hook');
@@ -131,13 +135,10 @@ function statusnet_jot_nets(&$a,&$b) {
                $statusnet_defpost = get_pconfig(local_user(),'statusnet','post_by_default');
                $selected = ((intval($statusnet_defpost) == 1) ? ' checked="checked" ' : '');
                $b .= '<div class="profile-jot-net"><input type="checkbox" name="statusnet_enable"' . $selected . ' value="1" /> ' 
-                       . t('Post to StatusNet') . '</div>';    
+                       . t('Post to StatusNet') . '</div>';
        }
 }
 
-
-
-
 function statusnet_settings_post ($a,$post) {
        if(! local_user())
            return;
@@ -148,14 +149,17 @@ function statusnet_settings_post ($a,$post) {
             /***
              * if the statusnet-disconnect checkbox is set, clear the statusnet configuration
              */
-            del_pconfig( local_user(), 'statusnet', 'consumerkey'  );
-            del_pconfig( local_user(), 'statusnet', 'consumersecret' );
-            del_pconfig( local_user(), 'statusnet', 'post' );
-            del_pconfig( local_user(), 'statusnet', 'post_by_default' );
-            del_pconfig( local_user(), 'statusnet', 'oauthtoken' );
-            del_pconfig( local_user(), 'statusnet', 'oauthsecret' );
-            del_pconfig( local_user(), 'statusnet', 'baseapi' );
-            del_pconfig( local_user(), 'statusnet', 'post_taglinks');
+            del_pconfig(local_user(), 'statusnet', 'consumerkey');
+            del_pconfig(local_user(), 'statusnet', 'consumersecret');
+            del_pconfig(local_user(), 'statusnet', 'post');
+            del_pconfig(local_user(), 'statusnet', 'post_by_default');
+            del_pconfig(local_user(), 'statusnet', 'oauthtoken');
+            del_pconfig(local_user(), 'statusnet', 'oauthsecret');
+            del_pconfig(local_user(), 'statusnet', 'baseapi');
+            del_pconfig(local_user(), 'statusnet', 'post_taglinks');
+            del_pconfig(local_user(), 'statusnet', 'lastid');
+            del_pconfig(local_user(), 'statusnet', 'mirror_posts');
+            del_pconfig(local_user(), 'statusnet', 'intelligent_shortening');
        } else {
             if (isset($_POST['statusnet-preconf-apiurl'])) {
                 /***
@@ -172,6 +176,7 @@ function statusnet_settings_post ($a,$post) {
                             set_pconfig(local_user(), 'statusnet', 'consumerkey', $asn['consumerkey'] );
                             set_pconfig(local_user(), 'statusnet', 'consumersecret', $asn['consumersecret'] );
                             set_pconfig(local_user(), 'statusnet', 'baseapi', $asn['apiurl'] );
+                            set_pconfig(local_user(), 'statusnet', 'application_name', $asn['applicationname'] );
                         } else {
                             notice( t('Please contact your site administrator.<br />The provided API URL is not valid.').EOL.$asn['apiurl'].EOL );
                         }
@@ -190,6 +195,7 @@ function statusnet_settings_post ($a,$post) {
                     set_pconfig(local_user(), 'statusnet', 'consumerkey', $_POST['statusnet-consumerkey']);
                     set_pconfig(local_user(), 'statusnet', 'consumersecret', $_POST['statusnet-consumersecret']);
                     set_pconfig(local_user(), 'statusnet', 'baseapi', $apibase );
+                    set_pconfig(local_user(), 'statusnet', 'application_name', $_POST['statusnet-applicationname'] );
                 } else {
                     //  the API path is not correct, maybe missing trailing / ?
                     $apibase = $apibase . '/';
@@ -207,7 +213,7 @@ function statusnet_settings_post ($a,$post) {
                 goaway($a->get_baseurl().'/settings/connectors');
             } else {
                if (isset($_POST['statusnet-pin'])) {
-                       //  if the user supplied us with a PIN from Twitter, let the magic of OAuth happen
+                       //  if the user supplied us with a PIN from StatusNet, let the magic of OAuth happen
                     $api     = get_pconfig(local_user(), 'statusnet', 'baseapi');
                                        $ckey    = get_pconfig(local_user(), 'statusnet', 'consumerkey'  );
                                        $csecret = get_pconfig(local_user(), 'statusnet', 'consumersecret' );
@@ -229,6 +235,8 @@ function statusnet_settings_post ($a,$post) {
                                        set_pconfig(local_user(),'statusnet','post',intval($_POST['statusnet-enable']));
                                         set_pconfig(local_user(),'statusnet','post_by_default',intval($_POST['statusnet-default']));
                                         set_pconfig(local_user(),'statusnet','post_taglinks',intval($_POST['statusnet-sendtaglinks']));
+                                       set_pconfig(local_user(), 'statusnet', 'mirror_posts', intval($_POST['statusnet-mirror']));
+                                       set_pconfig(local_user(), 'statusnet', 'intelligent_shortening', intval($_POST['statusnet-shortening']));
                                        info( t('StatusNet settings updated.') . EOL);
                }}}}
 }
@@ -253,6 +261,12 @@ function statusnet_settings(&$a,&$s) {
         $defchecked = (($defenabled) ? ' checked="checked" ' : '');
         $linksenabled = get_pconfig(local_user(),'statusnet','post_taglinks');
         $linkschecked = (($linksenabled) ? ' checked="checked" ' : '');
+
+       $mirrorenabled = get_pconfig(local_user(),'statusnet','mirror_posts');
+       $mirrorchecked = (($mirrorenabled) ? ' checked="checked" ' : '');
+       $shorteningenabled = get_pconfig(local_user(),'statusnet','intelligent_shortening');
+       $shorteningchecked = (($shorteningenabled) ? ' checked="checked" ' : '');
+
        $s .= '<div class="settings-block">';
        $s .= '<h3>'. t('StatusNet Posting Settings').'</h3>';
 
@@ -289,6 +303,9 @@ function statusnet_settings(&$a,&$s) {
             $s .= '<label id="statusnet-baseapi-label" for="statusnet-baseapi">'. t("Base API Path \x28remember the trailing /\x29") .'</label>';
             $s .= '<input id="statusnet-baseapi" type="text" name="statusnet-baseapi" size="35" /><br />';
             $s .= '<p></p><div class="clear"></div></div>';
+            $s .= '<label id="statusnet-applicationname-label" for="statusnet-applicationname">'.t('StatusNet application name').'</label>';
+            $s .= '<input id="statusnet-applicationname" type="text" name="statusnet-applicationname" size="35" /><br />';
+            $s .= '<p></p><div class="clear"></div></div>';
             $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="statusnet-submit" class="settings-submit" value="' . t('Submit') . '" /></div>';
        } else {
                /***
@@ -342,6 +359,15 @@ function statusnet_settings(&$a,&$s) {
                        $s .= '<label id="statusnet-default-label" for="statusnet-default">'. t('Send public postings to StatusNet by default') .'</label>';
                        $s .= '<input id="statusnet-default" type="checkbox" name="statusnet-default" value="1" ' . $defchecked . '/>';
                        $s .= '<div class="clear"></div>';
+
+                       $s .= '<label id="statusnet-mirror-label" for="statusnet-mirror">'.t('Mirror all posts from statusnet that are no replies or repeated messages').'</label>';
+                       $s .= '<input id="statusnet-mirror" type="checkbox" name="statusnet-mirror" value="1" '. $mirrorchecked . '/>';
+                       $s .= '<div class="clear"></div>';
+
+                       $s .= '<label id="statusnet-shortening-label" for="statusnet-shortening">'.t('Shortening method that optimizes the post').'</label>';
+                       $s .= '<input id="statusnet-shortening" type="checkbox" name="statusnet-shortening" value="1" '. $shorteningchecked . '/>';
+                       $s .= '<div class="clear"></div>';
+
                         $s .= '<label id="statusnet-sendtaglinks-label" for="statusnet-sendtaglinks">'.t('Send linked #-tags and @-names to StatusNet').'</label>';
                         $s .= '<input id="statusnet-sendtaglinks" type="checkbox" name="statusnet-sendtaglinks" value="1" '. $linkschecked . '/>';
                        $s .= '</div><div class="clear"></div>';
@@ -404,6 +430,131 @@ function short_link($url) {
     return $slinky->short();
 } };
 
+function statusnet_shortenmsg($b, $max_char) {
+       require_once("include/bbcode.php");
+       require_once("include/html2plain.php");
+
+       // Looking for the first image
+       $image = '';
+       if(preg_match("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/is",$b['body'],$matches))
+               $image = $matches[3];
+
+       if ($image == '')
+               if(preg_match("/\[img\](.*?)\[\/img\]/is",$b['body'],$matches))
+                       $image = $matches[1];
+
+       $multipleimages = (strpos($b['body'], "[img") != strrpos($b['body'], "[img"));
+
+       // When saved into the database the content is sent through htmlspecialchars
+       // That means that we have to decode all image-urls
+       $image = htmlspecialchars_decode($image);
+
+       $body = $b["body"];
+       if ($b["title"] != "")
+               $body = $b["title"]."\n\n".$body;
+
+       if (strpos($body, "[bookmark") !== false) {
+               // splitting the text in two parts:
+               // before and after the bookmark
+               $pos = strpos($body, "[bookmark");
+               $body1 = substr($body, 0, $pos);
+               $body2 = substr($body, $pos);
+
+               // Removing all quotes after the bookmark
+               // they are mostly only the content after the bookmark.
+               $body2 = preg_replace("/\[quote\=([^\]]*)\](.*?)\[\/quote\]/ism",'',$body2);
+               $body2 = preg_replace("/\[quote\](.*?)\[\/quote\]/ism",'',$body2);
+               $body = $body1.$body2;
+       }
+
+       // Add some newlines so that the message could be cut better
+       $body = str_replace(array("[quote", "[bookmark", "[/bookmark]", "[/quote]"),
+                               array("\n[quote", "\n[bookmark", "[/bookmark]\n", "[/quote]\n"), $body);
+
+       // remove the recycle signs and the names since they aren't helpful on twitter
+       // recycle 1
+       $recycle = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8');
+       $body = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', "\n", $body);
+       // recycle 2 (Test)
+       $recycle = html_entity_decode("&#x25CC; ", ENT_QUOTES, 'UTF-8');
+       $body = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', "\n", $body);
+
+       // remove the share element
+       $body = preg_replace("/\[share(.*?)\](.*?)\[\/share\]/ism","\n\n$2\n\n",$body);
+
+       // At first convert the text to html
+       $html = bbcode($body, false, false);
+
+       // Then convert it to plain text
+       //$msg = trim($b['title']." \n\n".html2plain($html, 0, true));
+       $msg = trim(html2plain($html, 0, true));
+       $msg = html_entity_decode($msg,ENT_QUOTES,'UTF-8');
+
+       // Removing multiple newlines
+       while (strpos($msg, "\n\n\n") !== false)
+               $msg = str_replace("\n\n\n", "\n\n", $msg);
+
+       // Removing multiple spaces
+       while (strpos($msg, "  ") !== false)
+               $msg = str_replace("  ", " ", $msg);
+
+       // Removing URLs
+       $msg = preg_replace('/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/i', "", $msg);
+
+       $msg = trim($msg);
+
+       $link = '';
+       // look for bookmark-bbcode and handle it with priority
+       if(preg_match("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/is",$b['body'],$matches))
+               $link = $matches[1];
+
+       $multiplelinks = (strpos($b['body'], "[bookmark") != strrpos($b['body'], "[bookmark"));
+
+       // If there is no bookmark element then take the first link
+       if ($link == '') {
+               $links = collecturls($html);
+               if (sizeof($links) > 0) {
+                       reset($links);
+                       $link = current($links);
+               }
+               $multiplelinks = (sizeof($links) > 1);
+       }
+
+       $msglink = "";
+       if ($multiplelinks)
+               $msglink = $b["plink"];
+       else if ($link != "")
+               $msglink = $link;
+       else if ($multipleimages)
+               $msglink = $b["plink"];
+       else if ($image != "")
+               $msglink = $image;
+
+       if (($msglink == "") and strlen($msg) > $max_char)
+               $msglink = $b["plink"];
+
+       if (strlen($msglink) > 20)
+               $msglink = short_link($msglink);
+
+       if (strlen(trim($msg." ".$msglink)) > $max_char) {
+               $msg = substr($msg, 0, $max_char - (strlen($msglink)));
+               $lastchar = substr($msg, -1);
+               $msg = substr($msg, 0, -1);
+               $pos = strrpos($msg, "\n");
+               if ($pos > 0)
+                       $msg = substr($msg, 0, $pos);
+               else if ($lastchar != "\n")
+                       $msg = substr($msg, 0, -3)."...";
+       }
+       $msg = str_replace("\n", " ", $msg);
+
+       // Removing multiple spaces - again
+       while (strpos($msg, "  ") !== false)
+               $msg = str_replace("  ", " ", $msg);
+
+       return(array("msg"=>trim($msg." ".$msglink), "image"=>$image));
+}
+
 function statusnet_post_hook(&$a,&$b) {
 
        /**
@@ -416,105 +567,136 @@ function statusnet_post_hook(&$a,&$b) {
        if(! strstr($b['postopts'],'statusnet'))
                return;
 
+       // if posts comes from statusnet don't send it back
+       if($b['app'] == "StatusNet")
+               return;
+
+        logger('statusnet post invoked');
+
        load_pconfig($b['uid'], 'statusnet');
-            
+
        $api     = get_pconfig($b['uid'], 'statusnet', 'baseapi');
-       $ckey    = get_pconfig($b['uid'], 'statusnet', 'consumerkey'  );
-       $csecret = get_pconfig($b['uid'], 'statusnet', 'consumersecret' );
-       $otoken  = get_pconfig($b['uid'], 'statusnet', 'oauthtoken'  );
-       $osecret = get_pconfig($b['uid'], 'statusnet', 'oauthsecret' );
+       $ckey    = get_pconfig($b['uid'], 'statusnet', 'consumerkey');
+       $csecret = get_pconfig($b['uid'], 'statusnet', 'consumersecret');
+       $otoken  = get_pconfig($b['uid'], 'statusnet', 'oauthtoken');
+       $osecret = get_pconfig($b['uid'], 'statusnet', 'oauthsecret');
+       $intelligent_shortening = get_pconfig($b['uid'], 'statusnet', 'intelligent_shortening');
+
+       // Global setting overrides this
+       if (get_config('statusnet','intelligent_shortening'))
+               $intelligent_shortening = get_config('statusnet','intelligent_shortening');
 
        if($ckey && $csecret && $otoken && $osecret) {
 
                require_once('include/bbcode.php');
                $dent = new StatusNetOAuth($api,$ckey,$csecret,$otoken,$osecret);
                 $max_char = $dent->get_maxlength(); // max. length for a dent
-                // we will only work with up to two times the length of the dent 
+                // we will only work with up to two times the length of the dent
                 // we can later send to StatusNet. This way we can "gain" some
                 // information during shortening of potential links but do not
                 // shorten all the links in a 200000 character long essay.
-                if (! $b['title']=='') {
-                       $tmp = $b['title'].": \n".$b['body'];
-//                    $tmp = substr($tmp, 0, 4*$max_char);
-                } else {
-                    $tmp = $b['body']; // substr($b['body'], 0, 3*$max_char);
-                }
-                // if [url=bla][img]blub.png[/img][/url] get blub.png
-                $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\]\[img\](\\w+.*?)\\[\\/img\]\\[\\/url\]/i', '$2', $tmp);
-                // preserve links to images, videos and audios
-                $tmp = preg_replace( '/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism', '$3', $tmp);
-                $tmp = preg_replace( '/\[\\/?img(\\s+.*?\]|\])/i', '', $tmp);
-                $tmp = preg_replace( '/\[\\/?video(\\s+.*?\]|\])/i', '', $tmp);
-                $tmp = preg_replace( '/\[\\/?youtube(\\s+.*?\]|\])/i', '', $tmp);
-                $tmp = preg_replace( '/\[\\/?vimeo(\\s+.*?\]|\])/i', '', $tmp);
-                $tmp = preg_replace( '/\[\\/?audio(\\s+.*?\]|\])/i', '', $tmp);
-                $linksenabled = get_pconfig($b['uid'],'statusnet','post_taglinks');
-                // if a #tag is linked, don't send the [url] over to SN
-                // that is, don't send if the option is not set in the 
-                // connector settings
-                if ($linksenabled=='0') {
-                       // #-tags
-                       $tmp = preg_replace( '/#\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '#$2', $tmp);
-                       // @-mentions
-                       $tmp = preg_replace( '/@\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '@$2', $tmp);
-                       // recycle 1
-                       $recycle = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8');
-                       $tmp = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', $recycle.'$2', $tmp);
-                       // recycle 2 (test)
-                       $recycle = html_entity_decode("&#x25CC; ", ENT_QUOTES, 'UTF-8');
-                       $tmp = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', $recycle.'$2', $tmp);
-                }
-                // preserve links to webpages
-                $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\](\w+.*?)\[\/url\]/i', '$2 $1', $tmp);
-                $tmp = preg_replace( '/\[bookmark\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\](\w+.*?)\[\/bookmark\]/i', '$2 $1', $tmp);
-                // find all http or https links in the body of the entry and 
-                // apply the shortener if the link is longer then 20 characters 
-                if (( strlen($tmp)>$max_char ) && ( $max_char > 0 )) {
-                    preg_match_all ( '/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/i', $tmp, $allurls  );
-                    foreach ($allurls as $url) {
-                        foreach ($url as $u) {
-                            if (strlen($u)>20) {
-                                $sl = short_link($u);
-                                $tmp = str_replace( $u, $sl, $tmp );
-                            }
-                        }
-                    }
-                }
-                // ok, all the links we want to send out are save, now strip 
-                // away the remaining bbcode
-               //$msg = strip_tags(bbcode($tmp, false, false));
-               $msg = bbcode($tmp, false, false);
-               $msg = str_replace(array('<br>','<br />'),"\n",$msg);
-               $msg = strip_tags($msg);
-
-               // quotes not working - let's try this
-               $msg = html_entity_decode($msg);
-
-               if (( strlen($msg) > $max_char) && $max_char > 0) {
-                       $shortlink = short_link( $b['plink'] );
-                       // the new message will be shortened such that "... $shortlink"
-                       // will fit into the character limit
-                       $msg = nl2br(substr($msg, 0, $max_char-strlen($shortlink)-4));
-                        $msg = str_replace(array('<br>','<br />'),' ',$msg);
-                        $e = explode(' ', $msg);
-                        //  remove the last word from the cut down message to 
-                        //  avoid sending cut words to the MicroBlog
-                        array_pop($e);
-                        $msg = implode(' ', $e);
-                       $msg .= '... ' . $shortlink;
-               }
 
-               $msg = trim($msg);
+               $tempfile = "";
+               $intelligent_shortening = get_config('statusnet','intelligent_shortening');
+               if (!$intelligent_shortening) {
+                       if (! $b['title']=='') {
+                               $tmp = $b['title'].": \n".$b['body'];
+       //                    $tmp = substr($tmp, 0, 4*$max_char);
+                       } else {
+                           $tmp = $b['body']; // substr($b['body'], 0, 3*$max_char);
+                       }
+                       // if [url=bla][img]blub.png[/img][/url] get blub.png
+                       $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\]\[img\](\\w+.*?)\\[\\/img\]\\[\\/url\]/i', '$2', $tmp);
+                       // preserve links to images, videos and audios
+                       $tmp = preg_replace( '/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism', '$3', $tmp);
+                       $tmp = preg_replace( '/\[\\/?img(\\s+.*?\]|\])/i', '', $tmp);
+                       $tmp = preg_replace( '/\[\\/?video(\\s+.*?\]|\])/i', '', $tmp);
+                       $tmp = preg_replace( '/\[\\/?youtube(\\s+.*?\]|\])/i', '', $tmp);
+                       $tmp = preg_replace( '/\[\\/?vimeo(\\s+.*?\]|\])/i', '', $tmp);
+                       $tmp = preg_replace( '/\[\\/?audio(\\s+.*?\]|\])/i', '', $tmp);
+                       $linksenabled = get_pconfig($b['uid'],'statusnet','post_taglinks');
+                       // if a #tag is linked, don't send the [url] over to SN
+                       // that is, don't send if the option is not set in the 
+                       // connector settings
+                       if ($linksenabled=='0') {
+                               // #-tags
+                               $tmp = preg_replace( '/#\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '#$2', $tmp);
+                               // @-mentions
+                               $tmp = preg_replace( '/@\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '@$2', $tmp);
+                               // recycle 1
+                               $recycle = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8');
+                               $tmp = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', $recycle.'$2', $tmp);
+                               // recycle 2 (test)
+                               $recycle = html_entity_decode("&#x25CC; ", ENT_QUOTES, 'UTF-8');
+                               $tmp = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', $recycle.'$2', $tmp);
+                       }
+                       // preserve links to webpages
+                       $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\](\w+.*?)\[\/url\]/i', '$2 $1', $tmp);
+                       $tmp = preg_replace( '/\[bookmark\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\](\w+.*?)\[\/bookmark\]/i', '$2 $1', $tmp);
+                       // find all http or https links in the body of the entry and 
+                       // apply the shortener if the link is longer then 20 characters 
+                       if (( strlen($tmp)>$max_char ) && ( $max_char > 0 )) {
+                           preg_match_all ( '/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/i', $tmp, $allurls  );
+                           foreach ($allurls as $url) {
+                               foreach ($url as $u) {
+                                   if (strlen($u)>20) {
+                                       $sl = short_link($u);
+                                       $tmp = str_replace( $u, $sl, $tmp );
+                                   }
+                               }
+                           }
+                       }
+                       // ok, all the links we want to send out are save, now strip 
+                       // away the remaining bbcode
+                       //$msg = strip_tags(bbcode($tmp, false, false));
+                       $msg = bbcode($tmp, false, false);
+                       $msg = str_replace(array('<br>','<br />'),"\n",$msg);
+                       $msg = strip_tags($msg);
+
+                       // quotes not working - let's try this
+                       $msg = html_entity_decode($msg);
+
+                       if (( strlen($msg) > $max_char) && $max_char > 0) {
+                               $shortlink = short_link( $b['plink'] );
+                               // the new message will be shortened such that "... $shortlink"
+                               // will fit into the character limit
+                               $msg = nl2br(substr($msg, 0, $max_char-strlen($shortlink)-4));
+                               $msg = str_replace(array('<br>','<br />'),' ',$msg);
+                               $e = explode(' ', $msg);
+                               //  remove the last word from the cut down message to 
+                               //  avoid sending cut words to the MicroBlog
+                               array_pop($e);
+                               $msg = implode(' ', $e);
+                               $msg .= '... ' . $shortlink;
+                       }
+
+                       $msg = trim($msg);
+                       $postdata = array('status' => $msg);
+               } else {
+                       $msgarr = statusnet_shortenmsg($b, $max_char);
+                       $msg = $msgarr["msg"];
+                       $image = $msgarr["image"];
+                       if ($image != "") {
+                               $imagedata = file_get_contents($image);
+                               $tempfile = tempnam(get_config("system","temppath"), "upload");
+                               file_put_contents($tempfile, $imagedata);
+                               $postdata = array("status"=>$msg, "media"=>"@".$tempfile);
+                       } else
+                               $postdata = array("status"=>$msg);
+               }
 
                // and now dent it :-)
                if(strlen($msg)) {
-                    $result = $dent->post('statuses/update', array('status' => $msg));
+                    //$result = $dent->post('statuses/update', array('status' => $msg));
+                    $result = $dent->post('statuses/update', $postdata);
                     logger('statusnet_post send, result: ' . print_r($result, true).
-                           "\nmessage: ".$msg, LOGGER_DEBUG."\nOriginal post: ".print_r($b));
+                           "\nmessage: ".$msg, LOGGER_DEBUG."\nOriginal post: ".print_r($b, true)."\nPost Data: ".print_r($postdata, true));
                     if ($result->error) {
                         logger('Send to StatusNet failed: "' . $result->error . '"');
                     }
                 }
+               if ($tempfile != "")
+                       unlink($tempfile);
        }
 }
 
@@ -527,6 +709,7 @@ function statusnet_plugin_admin_post(&$a){
                $apiurl=trim($_POST['apiurl'][$id]);
                $secret=trim($_POST['secret'][$id]);
                $key=trim($_POST['key'][$id]);
+                $applicationname = ((x($_POST, 'applicationname')) ? notags(trim($_POST['applicationname'][$id])):'');
                if ($sitename!="" &&
                        $apiurl!="" &&
                        $secret!="" &&
@@ -537,7 +720,8 @@ function statusnet_plugin_admin_post(&$a){
                                        'sitename' => $sitename,
                                        'apiurl' => $apiurl,
                                        'consumersecret' => $secret,
-                                       'consumerkey' => $key
+                                       'consumerkey' => $key,
+                                        'applicationname' => $applicationname
                                );
                }
        }
@@ -557,6 +741,7 @@ function statusnet_plugin_admin(&$a, &$o){
                                'apiurl' => Array("apiurl[$id]", "Api url", $s['apiurl'], ""),
                                'secret' => Array("secret[$id]", "Secret", $s['consumersecret'], ""),
                                'key' => Array("key[$id]", "Key", $s['consumerkey'], ""),
+                               'applicationname' => Array("applicationname[$id]", "Application name", $s['applicationname'], ""),
                                'delete' => Array("delete[$id]", "Delete", False , "Check to delete this preset"),
                        );
                }
@@ -568,16 +753,126 @@ function statusnet_plugin_admin(&$a, &$o){
                'apiurl' => Array("apiurl[$id]", t("API URL"), "", ""),
                'secret' => Array("secret[$id]", t("Consumer Secret"), "", ""),
                'key' => Array("key[$id]", t("Consumer Key"), "", ""),
+               'applicationname' => Array("applicationname[$id]", t("Application name"), "", ""),
        );
 
-       
-       $t = file_get_contents( dirname(__file__). "/admin.tpl" );
+       $t = get_markup_template( "admin.tpl", "addon/statusnet/" );
        $o = replace_macros($t, array(
                '$submit' => t('Submit'),
-                                                       
                '$sites' => $sitesform,
-               
        ));
-       
-       
 }
+
+function statusnet_cron($a,$b) {
+       $last = get_config('statusnet','last_poll');
+
+       $poll_interval = intval(get_config('statusnet','poll_interval'));
+       if(! $poll_interval)
+               $poll_interval = STATUSNET_DEFAULT_POLL_INTERVAL;
+
+       if($last) {
+               $next = $last + ($poll_interval * 60);
+               if($next > time()) {
+                       logger('statusnet: poll intervall not reached');
+                       return;
+               }
+       }
+       logger('statusnet: cron_start');
+
+       $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'statusnet' AND `k` = 'mirror_posts' AND `v` = '1' ORDER BY RAND() ");
+       if(count($r)) {
+               foreach($r as $rr) {
+                       logger('statusnet: fetching for user '.$rr['uid']);
+                       statusnet_fetchtimeline($a, $rr['uid']);
+               }
+       }
+
+       logger('statusnet: cron_end');
+
+       set_config('statusnet','last_poll', time());
+}
+
+function statusnet_fetchtimeline($a, $uid) {
+       $ckey    = get_pconfig($uid, 'statusnet', 'consumerkey');
+       $csecret = get_pconfig($uid, 'statusnet', 'consumersecret');
+       $api     = get_pconfig($uid, 'statusnet', 'baseapi');
+       $otoken  = get_pconfig($uid, 'statusnet', 'oauthtoken');
+       $osecret = get_pconfig($uid, 'statusnet', 'oauthsecret');
+       $lastid  = get_pconfig($uid, 'statusnet', 'lastid');
+
+        //  get the application name for the SN app
+        //  1st try personal config, then system config and fallback to the 
+        //  hostname of the node if neither one is set. 
+        $application_name  = get_pconfig( $uid, 'statusnet', 'application_name');
+        if ($application_name == "")
+               $application_name  = get_config('statusnet', 'application_name');
+       if ($application_name == "")
+               $application_name = $a->get_hostname();
+
+       $connection = new StatusNetOAuth($api, $ckey,$csecret,$otoken,$osecret);
+
+       $parameters = array("exclude_replies" => true, "trim_user" => true, "contributor_details" => false, "include_rts" => false);
+
+       $first_time = ($lastid == "");
+
+       if ($lastid <> "")
+               $parameters["since_id"] = $lastid;
+
+       $items = $connection->get('statuses/user_timeline', $parameters);
+
+       if (!is_array($items))
+               return;
+
+       $posts = array_reverse($items);
+
+        if (count($posts)) {
+            foreach ($posts as $post) {
+               if ($post->id > $lastid)
+                       $lastid = $post->id;
+
+               if ($first_time)
+                       continue;
+
+               if (is_object($post->retweeted_status))
+                       continue;
+
+               if ($post->in_reply_to_status_id != "")
+                       continue;
+
+               if (!strpos($post->source, $application_name)) {
+                       $_SESSION["authenticated"] = true;
+                       $_SESSION["uid"] = $uid;
+
+                       $_REQUEST["type"] = "wall";
+                       $_REQUEST["api_source"] = true;
+                       $_REQUEST["profile_uid"] = $uid;
+                       $_REQUEST["source"] = "StatusNet";
+
+                       //$_REQUEST["date"] = $post->created_at;
+
+                       $_REQUEST["body"] = $post->text;
+                       if (is_string($post->place->name))
+                               $_REQUEST["location"] = $post->place->name;
+
+                       if (is_string($post->place->full_name))
+                               $_REQUEST["location"] = $post->place->full_name;
+
+                       if (is_array($post->geo->coordinates))
+                               $_REQUEST["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
+
+                       if (is_array($post->coordinates->coordinates))
+                               $_REQUEST["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
+
+                       //print_r($_REQUEST);
+                       if ($_REQUEST["body"] != "") {
+                               logger('statusnet: posting for user '.$uid);
+
+                               require_once('mod/item.php');
+                               item_post($a);
+                       }
+                }
+            }
+       }
+       set_pconfig($uid, 'statusnet', 'lastid', $lastid);
+}
+
diff --git a/statusnet/view/admin.tpl b/statusnet/view/admin.tpl
new file mode 100644 (file)
index 0000000..686a4c7
--- /dev/null
@@ -0,0 +1,17 @@
+{{ for $sites as $s }}
+       {{ inc field_input.tpl with $field=$s.sitename }}{{ endinc }}
+       {{ inc field_input.tpl with $field=$s.apiurl }}{{ endinc }}
+       {{ inc field_input.tpl with $field=$s.secret }}{{ endinc }}
+       {{ inc field_input.tpl with $field=$s.key }}{{ endinc }}
+       {{ inc field_input.tpl with $field=$s.applicationname }}{{ endinc }}
+       {{ if $s.delete }}
+               {{ inc field_checkbox.tpl with $field=$s.delete }}{{ endinc }}
+               <hr>
+       {{ else }}
+               <p>Fill this form to add a new site</p>
+       {{ endif }}
+       
+{{ endfor }}
+
+
+<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
diff --git a/statusnet/view/smarty3/admin.tpl b/statusnet/view/smarty3/admin.tpl
new file mode 100644 (file)
index 0000000..f8d14c6
--- /dev/null
@@ -0,0 +1,17 @@
+{{foreach $sites as $s}}
+       {{include file="field_input.tpl" field=$s.sitename}}
+       {{include file="field_input.tpl" field=$s.apiurl}}
+       {{include file="field_input.tpl" field=$s.secret}}
+       {{include file="field_input.tpl" field=$s.key}}
+       {{include file="field_input.tpl" field=$s.applicationname}}
+       {{if $s.delete}}
+               {{include file="field_checkbox.tpl" field=$s.delete}}
+               <hr>
+       {{else}}
+               <p>Fill this form to add a new site</p>
+       {{/if}}
+       
+{{/foreach}}
+
+
+<div class="submit"><input type="submit" name="page_site" value="{{$submit}}" /></div>
index fe03895547fb581ab75571aa33ce6cd85cd0679b..b4f6ff9b7b098fddef0af87f795d6c6f49082d8b 100755 (executable)
Binary files a/tumblr.tgz and b/tumblr.tgz differ
diff --git a/tumblr/README b/tumblr/README
new file mode 100644 (file)
index 0000000..62d7fd0
--- /dev/null
@@ -0,0 +1,9 @@
+Define in your .htconfig.php:
+$a->config['tumblr']['consumer_key'] = "your-consumer-key";
+$a->config['tumblr']['consumer_secret'] = "your-consumer-secret";
+
+You can get it here:
+http://www.tumblr.com/oauth/apps
+
+Tumblr-OAuth-Library:
+https://groups.google.com/d/msg/tumblr-api/g6SeIBWvsnE/gnWqT9jFSlEJ
index eeb51348ba65e799113974b3a0f81c6926ead494..4bbae8e6c06c47234e80d7dc414737fac1900b41 100755 (executable)
@@ -7,6 +7,9 @@
  * Author: Mike Macgirvin <http://macgirvin.com/profile/mike>
  */
 
+require_once('library/OAuth1.php');
+require_once('addon/tumblr/tumblroauth/tumblroauth.php');
+
 function tumblr_install() {
     register_hook('post_local',           'addon/tumblr/tumblr.php', 'tumblr_post_local');
     register_hook('notifier_normal',      'addon/tumblr/tumblr.php', 'tumblr_send');
@@ -23,6 +26,125 @@ function tumblr_uninstall() {
     unregister_hook('connector_settings_post', 'addon/tumblr/tumblr.php', 'tumblr_settings_post');
 }
 
+function tumblr_module() {}
+
+function tumblr_content(&$a) {
+
+       if(! local_user()) {
+               notice( t('Permission denied.') . EOL);
+               return '';
+       }
+
+       if (isset($a->argv[1]))
+               switch ($a->argv[1]) {
+                       case "connect":
+                               $o = tumblr_connect($a);
+                               break;
+                       case "callback":
+                               $o = tumblr_callback($a);
+                               break;
+                       default:
+                               $o = print_r($a->argv, true);
+                               break;
+               }
+       else
+               $o = tumblr_connect($a);
+
+       return $o;
+}
+
+function tumblr_connect($a) {
+       // Start a session.  This is necessary to hold on to  a few keys the callback script will also need
+       session_start();
+
+       // Include the TumblrOAuth library
+       //require_once('addon/tumblr/tumblroauth/tumblroauth.php');
+
+       // Define the needed keys
+       $consumer_key = get_config('tumblr','consumer_key');
+       $consumer_secret = get_config('tumblr','consumer_secret');
+
+       // The callback URL is the script that gets called after the user authenticates with tumblr
+       // In this example, it would be the included callback.php
+       $callback_url = $a->get_baseurl()."/tumblr/callback";
+
+       // Let's begin.  First we need a Request Token.  The request token is required to send the user
+       // to Tumblr's login page.
+
+       // Create a new instance of the TumblrOAuth library.  For this step, all we need to give the library is our
+       // Consumer Key and Consumer Secret
+       $tum_oauth = new TumblrOAuth($consumer_key, $consumer_secret);
+
+       // Ask Tumblr for a Request Token.  Specify the Callback URL here too (although this should be optional)
+       $request_token = $tum_oauth->getRequestToken($callback_url);
+
+       // Store the request token and Request Token Secret as out callback.php script will need this
+       $_SESSION['request_token'] = $token = $request_token['oauth_token'];
+       $_SESSION['request_token_secret'] = $request_token['oauth_token_secret'];
+
+       // Check the HTTP Code.  It should be a 200 (OK), if it's anything else then something didn't work.
+       switch ($tum_oauth->http_code) {
+         case 200:
+           // Ask Tumblr to give us a special address to their login page
+           $url = $tum_oauth->getAuthorizeURL($token);
+
+               // Redirect the user to the login URL given to us by Tumblr
+           header('Location: ' . $url);
+
+               // That's it for our side.  The user is sent to a Tumblr Login page and
+               // asked to authroize our app.  After that, Tumblr sends the user back to
+               // our Callback URL (callback.php) along with some information we need to get
+               // an access token.
+
+           break;
+       default:
+           // Give an error message
+           $o = 'Could not connect to Tumblr. Refresh the page or try again later.';
+       }
+       return($o);
+}
+
+function tumblr_callback($a) {
+
+       // Start a session, load the library
+       session_start();
+       //require_once('addon/tumblr/tumblroauth/tumblroauth.php');
+
+       // Define the needed keys
+       $consumer_key = get_config('tumblr','consumer_key');
+       $consumer_secret = get_config('tumblr','consumer_secret');
+
+       // Once the user approves your app at Tumblr, they are sent back to this script.
+       // This script is passed two parameters in the URL, oauth_token (our Request Token)
+       // and oauth_verifier (Key that we need to get Access Token).
+       // We'll also need out Request Token Secret, which we stored in a session.
+
+       // Create instance of TumblrOAuth.
+       // It'll need our Consumer Key and Secret as well as our Request Token and Secret
+       $tum_oauth = new TumblrOAuth($consumer_key, $consumer_secret, $_SESSION['request_token'], $_SESSION['request_token_secret']);
+
+       // Ok, let's get an Access Token. We'll need to pass along our oauth_verifier which was given to us in the URL. 
+       $access_token = $tum_oauth->getAccessToken($_REQUEST['oauth_verifier']);
+
+       // We're done with the Request Token and Secret so let's remove those.
+       unset($_SESSION['request_token']);
+       unset($_SESSION['request_token_secret']);
+
+       // Make sure nothing went wrong.
+       if (200 == $tum_oauth->http_code) {
+         // good to go
+       } else {
+         return('Unable to authenticate');
+       }
+
+       // What's next?  Now that we have an Access Token and Secret, we can make an API call.
+       set_pconfig(local_user(), "tumblr", "oauth_token", $access_token['oauth_token']);
+       set_pconfig(local_user(), "tumblr", "oauth_token_secret", $access_token['oauth_token_secret']);
+
+       $o = t("You are now authenticated to tumblr.");
+       $o .= '<br /><a href="'.$a->get_baseurl().'/settings/connectors">'.t("return to the connector page").'</a>';
+       return($o);
+}
 
 function tumblr_jot_nets(&$a,&$b) {
     if(! local_user())
@@ -57,27 +179,18 @@ function tumblr_settings(&$a,&$s) {
 
     $def_checked = (($def_enabled) ? ' checked="checked" ' : '');
 
-       $tmbl_username = get_pconfig(local_user(), 'tumblr', 'tumblr_username');
-       $tmbl_password = get_pconfig(local_user(), 'tumblr', 'tumblr_password');
-
-
     /* Add some HTML to the existing form */
 
     $s .= '<div class="settings-block">';
     $s .= '<h3>' . t('Tumblr Post Settings') . '</h3>';
-    $s .= '<div id="tumblr-enable-wrapper">';
-    $s .= '<label id="tumblr-enable-label" for="tumblr-checkbox">' . t('Enable Tumblr Post Plugin') . '</label>';
-    $s .= '<input id="tumblr-checkbox" type="checkbox" name="tumblr" value="1" ' . $checked . '/>';
-    $s .= '</div><div class="clear"></div>';
 
     $s .= '<div id="tumblr-username-wrapper">';
-    $s .= '<label id="tumblr-username-label" for="tumblr-username">' . t('Tumblr login') . '</label>';
-    $s .= '<input id="tumblr-username" type="text" name="tumblr_username" value="' . $tmbl_username . '" />';
+    $s .= '<a href="'.$a->get_baseurl().'/tumblr/connect">'.t("(Re-)Authenticate your tumblr page").'</a>';
     $s .= '</div><div class="clear"></div>';
 
-    $s .= '<div id="tumblr-password-wrapper">';
-    $s .= '<label id="tumblr-password-label" for="tumblr-password">' . t('Tumblr password') . '</label>';
-    $s .= '<input id="tumblr-password" type="password" name="tumblr_password" value="' . $tmbl_password . '" />';
+    $s .= '<div id="tumblr-enable-wrapper">';
+    $s .= '<label id="tumblr-enable-label" for="tumblr-checkbox">' . t('Enable Tumblr Post Plugin') . '</label>';
+    $s .= '<input id="tumblr-checkbox" type="checkbox" name="tumblr" value="1" ' . $checked . '/>';
     $s .= '</div><div class="clear"></div>';
 
     $s .= '<div id="tumblr-bydefault-wrapper">';
@@ -85,6 +198,36 @@ function tumblr_settings(&$a,&$s) {
     $s .= '<input id="tumblr-bydefault" type="checkbox" name="tumblr_bydefault" value="1" ' . $def_checked . '/>';
     $s .= '</div><div class="clear"></div>';
 
+    $oauth_token = get_pconfig(local_user(), "tumblr", "oauth_token");
+    $oauth_token_secret = get_pconfig(local_user(), "tumblr", "oauth_token_secret");
+
+    $s .= '<div id="tumblr-password-wrapper">';
+    if (($oauth_token != "") and ($oauth_token_secret != "")) {
+
+       $page = get_pconfig(local_user(),'tumblr','page');
+       $consumer_key = get_config('tumblr','consumer_key');
+       $consumer_secret = get_config('tumblr','consumer_secret');
+
+       $tum_oauth = new TumblrOAuth($consumer_key, $consumer_secret, $oauth_token, $oauth_token_secret);
+
+       $userinfo = $tum_oauth->get('user/info');
+
+       $blogs = array();
+
+       $s .= t("Post to page:")."<select name='tumblr_page'>";
+       foreach($userinfo->response->user->blogs as $blog) {
+               $blogurl = substr(str_replace(array("http://", "https://"), array("", ""), $blog->url), 0, -1);
+               if ($page == $blogurl)
+                       $s .= "<option value='".$blogurl."' selected>".$blogurl."</option>";
+               else
+                       $s .= "<option value='".$blogurl."'>".$blogurl."</option>";
+       }
+
+       $s .= "</select>";
+    } else
+       $s .= t("You are not authenticated to tumblr");
+    $s .= '</div><div class="clear"></div>';
+
     /* provide a submit button */
 
     $s .= '<div class="settings-submit-wrapper" ><input type="submit" id="tumblr-submit" name="tumblr-submit" class="settings-submit" value="' . t('Submit') . '" /></div></div>';
@@ -97,9 +240,8 @@ function tumblr_settings_post(&$a,&$b) {
        if(x($_POST,'tumblr-submit')) {
 
                set_pconfig(local_user(),'tumblr','post',intval($_POST['tumblr']));
+               set_pconfig(local_user(),'tumblr','page',$_POST['tumblr_page']);
                set_pconfig(local_user(),'tumblr','post_by_default',intval($_POST['tumblr_bydefault']));
-               set_pconfig(local_user(),'tumblr','tumblr_username',trim($_POST['tumblr_username']));
-               set_pconfig(local_user(),'tumblr','tumblr_password',trim($_POST['tumblr_password']));
 
        }
 
@@ -147,12 +289,12 @@ function tumblr_send(&$a,&$b) {
     if($b['parent'] != $b['id'])
         return;
 
+       $oauth_token = get_pconfig($b['uid'], "tumblr", "oauth_token");
+       $oauth_token_secret = get_pconfig($b['uid'], "tumblr", "oauth_token_secret");
+       $page = get_pconfig($b['uid'], "tumblr", "page");
+       $tmbl_blog = 'blog/'.$page.'/post';
 
-       $tmbl_username = get_pconfig($b['uid'],'tumblr','tumblr_username');
-       $tmbl_password = get_pconfig($b['uid'],'tumblr','tumblr_password');
-       $tmbl_blog = 'http://www.tumblr.com/api/write';
-
-       if($tmbl_username && $tmbl_password && $tmbl_blog) {
+       if($oauth_token && $oauth_token_secret && $tmbl_blog) {
 
                require_once('include/bbcode.php');
 
@@ -193,10 +335,8 @@ function tumblr_send(&$a,&$b) {
                }
 
                $params = array(
-                       'email' => $tmbl_username,
-                       'password' => $tmbl_password,
                        'format' => 'html',
-                       'generator' => 'Friendica',
+                       'tweet' => 'off',
                        'tags' => $tags);
 
                if (($link != '') and $video) {
@@ -209,17 +349,25 @@ function tumblr_send(&$a,&$b) {
                                $params['caption'] = bbcode($body, false, false);
                } else if (($link != '') and !$video) {
                        $params['type'] = "link";
-                       $params['name'] = $title;
+                       $params['title'] = $title;
                        $params['url'] = $link;
                        $params['description'] = bbcode($b["body"], false, false);
                } else {
-                       $params['type'] = "regular";
+                       $params['type'] = "text";
                        $params['title'] = $title;
                        $params['body'] = bbcode($b['body'], false, false);
                }
 
-               $x = post_url($tmbl_blog,$params);
-               $ret_code = $a->get_curl_code();
+               $consumer_key = get_config('tumblr','consumer_key');
+               $consumer_secret = get_config('tumblr','consumer_secret');
+
+               $tum_oauth = new TumblrOAuth($consumer_key, $consumer_secret, $oauth_token, $oauth_token_secret);
+
+               // Make an API call with the TumblrOAuth instance.
+               $x = $tum_oauth->post($tmbl_blog,$params);
+
+               $ret_code = $tum_oauth->http_code;
+
                if($ret_code == 201)
                        logger('tumblr_send: success');
                elseif($ret_code == 403)
diff --git a/tumblr/tumblroauth/OAuth.php b/tumblr/tumblroauth/OAuth.php
new file mode 100644 (file)
index 0000000..982aaa5
--- /dev/null
@@ -0,0 +1,874 @@
+<?php\r
+// vim: foldmethod=marker\r
+\r
+/* Generic exception class\r
+ */\r
+class OAuthException extends Exception {\r
+  // pass\r
+}\r
+\r
+class OAuthConsumer {\r
+  public $key;\r
+  public $secret;\r
+\r
+  function __construct($key, $secret, $callback_url=NULL) {\r
+    $this->key = $key;\r
+    $this->secret = $secret;\r
+    $this->callback_url = $callback_url;\r
+  }\r
+\r
+  function __toString() {\r
+    return "OAuthConsumer[key=$this->key,secret=$this->secret]";\r
+  }\r
+}\r
+\r
+class OAuthToken {\r
+  // access tokens and request tokens\r
+  public $key;\r
+  public $secret;\r
+\r
+  /**\r
+   * key = the token\r
+   * secret = the token secret\r
+   */\r
+  function __construct($key, $secret) {\r
+    $this->key = $key;\r
+    $this->secret = $secret;\r
+  }\r
+\r
+  /**\r
+   * generates the basic string serialization of a token that a server\r
+   * would respond to request_token and access_token calls with\r
+   */\r
+  function to_string() {\r
+    return "oauth_token=" .\r
+           OAuthUtil::urlencode_rfc3986($this->key) .\r
+           "&oauth_token_secret=" .\r
+           OAuthUtil::urlencode_rfc3986($this->secret);\r
+  }\r
+\r
+  function __toString() {\r
+    return $this->to_string();\r
+  }\r
+}\r
+\r
+/**\r
+ * A class for implementing a Signature Method\r
+ * See section 9 ("Signing Requests") in the spec\r
+ */\r
+abstract class OAuthSignatureMethod {\r
+  /**\r
+   * Needs to return the name of the Signature Method (ie HMAC-SHA1)\r
+   * @return string\r
+   */\r
+  abstract public function get_name();\r
+\r
+  /**\r
+   * Build up the signature\r
+   * NOTE: The output of this function MUST NOT be urlencoded.\r
+   * the encoding is handled in OAuthRequest when the final\r
+   * request is serialized\r
+   * @param OAuthRequest $request\r
+   * @param OAuthConsumer $consumer\r
+   * @param OAuthToken $token\r
+   * @return string\r
+   */\r
+  abstract public function build_signature($request, $consumer, $token);\r
+\r
+  /**\r
+   * Verifies that a given signature is correct\r
+   * @param OAuthRequest $request\r
+   * @param OAuthConsumer $consumer\r
+   * @param OAuthToken $token\r
+   * @param string $signature\r
+   * @return bool\r
+   */\r
+  public function check_signature($request, $consumer, $token, $signature) {\r
+    $built = $this->build_signature($request, $consumer, $token);\r
+    return $built == $signature;\r
+  }\r
+}\r
+\r
+/**\r
+ * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] \r
+ * where the Signature Base String is the text and the key is the concatenated values (each first \r
+ * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&' \r
+ * character (ASCII code 38) even if empty.\r
+ *   - Chapter 9.2 ("HMAC-SHA1")\r
+ */\r
+class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {\r
+  function get_name() {\r
+    return "HMAC-SHA1";\r
+  }\r
+\r
+  public function build_signature($request, $consumer, $token) {\r
+    $base_string = $request->get_signature_base_string();\r
+    $request->base_string = $base_string;\r
+\r
+    $key_parts = array(\r
+      $consumer->secret,\r
+      ($token) ? $token->secret : ""\r
+    );\r
+\r
+    $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);\r
+    $key = implode('&', $key_parts);\r
+\r
+    return base64_encode(hash_hmac('sha1', $base_string, $key, true));\r
+  }\r
+}\r
+\r
+/**\r
+ * The PLAINTEXT method does not provide any security protection and SHOULD only be used \r
+ * over a secure channel such as HTTPS. It does not use the Signature Base String.\r
+ *   - Chapter 9.4 ("PLAINTEXT")\r
+ */\r
+class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {\r
+  public function get_name() {\r
+    return "PLAINTEXT";\r
+  }\r
+\r
+  /**\r
+   * oauth_signature is set to the concatenated encoded values of the Consumer Secret and \r
+   * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is \r
+   * empty. The result MUST be encoded again.\r
+   *   - Chapter 9.4.1 ("Generating Signatures")\r
+   *\r
+   * Please note that the second encoding MUST NOT happen in the SignatureMethod, as\r
+   * OAuthRequest handles this!\r
+   */\r
+  public function build_signature($request, $consumer, $token) {\r
+    $key_parts = array(\r
+      $consumer->secret,\r
+      ($token) ? $token->secret : ""\r
+    );\r
+\r
+    $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);\r
+    $key = implode('&', $key_parts);\r
+    $request->base_string = $key;\r
+\r
+    return $key;\r
+  }\r
+}\r
+\r
+/**\r
+ * The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in \r
+ * [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for \r
+ * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a \r
+ * verified way to the Service Provider, in a manner which is beyond the scope of this \r
+ * specification.\r
+ *   - Chapter 9.3 ("RSA-SHA1")\r
+ */\r
+abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {\r
+  public function get_name() {\r
+    return "RSA-SHA1";\r
+  }\r
+\r
+  // Up to the SP to implement this lookup of keys. Possible ideas are:\r
+  // (1) do a lookup in a table of trusted certs keyed off of consumer\r
+  // (2) fetch via http using a url provided by the requester\r
+  // (3) some sort of specific discovery code based on request\r
+  //\r
+  // Either way should return a string representation of the certificate\r
+  protected abstract function fetch_public_cert(&$request);\r
+\r
+  // Up to the SP to implement this lookup of keys. Possible ideas are:\r
+  // (1) do a lookup in a table of trusted certs keyed off of consumer\r
+  //\r
+  // Either way should return a string representation of the certificate\r
+  protected abstract function fetch_private_cert(&$request);\r
+\r
+  public function build_signature($request, $consumer, $token) {\r
+    $base_string = $request->get_signature_base_string();\r
+    $request->base_string = $base_string;\r
+\r
+    // Fetch the private key cert based on the request\r
+    $cert = $this->fetch_private_cert($request);\r
+\r
+    // Pull the private key ID from the certificate\r
+    $privatekeyid = openssl_get_privatekey($cert);\r
+\r
+    // Sign using the key\r
+    $ok = openssl_sign($base_string, $signature, $privatekeyid);\r
+\r
+    // Release the key resource\r
+    openssl_free_key($privatekeyid);\r
+\r
+    return base64_encode($signature);\r
+  }\r
+\r
+  public function check_signature($request, $consumer, $token, $signature) {\r
+    $decoded_sig = base64_decode($signature);\r
+\r
+    $base_string = $request->get_signature_base_string();\r
+\r
+    // Fetch the public key cert based on the request\r
+    $cert = $this->fetch_public_cert($request);\r
+\r
+    // Pull the public key ID from the certificate\r
+    $publickeyid = openssl_get_publickey($cert);\r
+\r
+    // Check the computed signature against the one passed in the query\r
+    $ok = openssl_verify($base_string, $decoded_sig, $publickeyid);\r
+\r
+    // Release the key resource\r
+    openssl_free_key($publickeyid);\r
+\r
+    return $ok == 1;\r
+  }\r
+}\r
+\r
+class OAuthRequest {\r
+  private $parameters;\r
+  private $http_method;\r
+  private $http_url;\r
+  // for debug purposes\r
+  public $base_string;\r
+  public static $version = '1.0';\r
+  public static $POST_INPUT = 'php://input';\r
+\r
+  function __construct($http_method, $http_url, $parameters=NULL) {\r
+    @$parameters or $parameters = array();\r
+    $parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);\r
+    $this->parameters = $parameters;\r
+    $this->http_method = $http_method;\r
+    $this->http_url = $http_url;\r
+  }\r
+\r
+\r
+  /**\r
+   * attempt to build up a request from what was passed to the server\r
+   */\r
+  public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {\r
+    $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")\r
+              ? 'http'\r
+              : 'https';\r
+    @$http_url or $http_url = $scheme .\r
+                              '://' . $_SERVER['HTTP_HOST'] .\r
+                              ':' .\r
+                              $_SERVER['SERVER_PORT'] .\r
+                              $_SERVER['REQUEST_URI'];\r
+    @$http_method or $http_method = $_SERVER['REQUEST_METHOD'];\r
+\r
+    // We weren't handed any parameters, so let's find the ones relevant to\r
+    // this request.\r
+    // If you run XML-RPC or similar you should use this to provide your own\r
+    // parsed parameter-list\r
+    if (!$parameters) {\r
+      // Find request headers\r
+      $request_headers = OAuthUtil::get_headers();\r
+\r
+      // Parse the query-string to find GET parameters\r
+      $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']);\r
+\r
+      // It's a POST request of the proper content-type, so parse POST\r
+      // parameters and add those overriding any duplicates from GET\r
+      if ($http_method == "POST"\r
+          && @strstr($request_headers["Content-Type"],\r
+                     "application/x-www-form-urlencoded")\r
+          ) {\r
+        $post_data = OAuthUtil::parse_parameters(\r
+          file_get_contents(self::$POST_INPUT)\r
+        );\r
+        $parameters = array_merge($parameters, $post_data);\r
+      }\r
+\r
+      // We have a Authorization-header with OAuth data. Parse the header\r
+      // and add those overriding any duplicates from GET or POST\r
+      if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") {\r
+        $header_parameters = OAuthUtil::split_header(\r
+          $request_headers['Authorization']\r
+        );\r
+        $parameters = array_merge($parameters, $header_parameters);\r
+      }\r
+\r
+    }\r
+\r
+    return new OAuthRequest($http_method, $http_url, $parameters);\r
+  }\r
+\r
+  /**\r
+   * pretty much a helper function to set up the request\r
+   */\r
+  public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {\r
+    @$parameters or $parameters = array();\r
+    $defaults = array("oauth_version" => OAuthRequest::$version,\r
+                      "oauth_nonce" => OAuthRequest::generate_nonce(),\r
+                      "oauth_timestamp" => OAuthRequest::generate_timestamp(),\r
+                      "oauth_consumer_key" => $consumer->key);\r
+    if ($token)\r
+      $defaults['oauth_token'] = $token->key;\r
+\r
+    $parameters = array_merge($defaults, $parameters);\r
+\r
+    return new OAuthRequest($http_method, $http_url, $parameters);\r
+  }\r
+\r
+  public function set_parameter($name, $value, $allow_duplicates = true) {\r
+    if ($allow_duplicates && isset($this->parameters[$name])) {\r
+      // We have already added parameter(s) with this name, so add to the list\r
+      if (is_scalar($this->parameters[$name])) {\r
+        // This is the first duplicate, so transform scalar (string)\r
+        // into an array so we can add the duplicates\r
+        $this->parameters[$name] = array($this->parameters[$name]);\r
+      }\r
+\r
+      $this->parameters[$name][] = $value;\r
+    } else {\r
+      $this->parameters[$name] = $value;\r
+    }\r
+  }\r
+\r
+  public function get_parameter($name) {\r
+    return isset($this->parameters[$name]) ? $this->parameters[$name] : null;\r
+  }\r
+\r
+  public function get_parameters() {\r
+    return $this->parameters;\r
+  }\r
+\r
+  public function unset_parameter($name) {\r
+    unset($this->parameters[$name]);\r
+  }\r
+\r
+  /**\r
+   * The request parameters, sorted and concatenated into a normalized string.\r
+   * @return string\r
+   */\r
+  public function get_signable_parameters() {\r
+    // Grab all parameters\r
+    $params = $this->parameters;\r
+\r
+    // Remove oauth_signature if present\r
+    // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")\r
+    if (isset($params['oauth_signature'])) {\r
+      unset($params['oauth_signature']);\r
+    }\r
+\r
+    return OAuthUtil::build_http_query($params);\r
+  }\r
+\r
+  /**\r
+   * Returns the base string of this request\r
+   *\r
+   * The base string defined as the method, the url\r
+   * and the parameters (normalized), each urlencoded\r
+   * and the concated with &.\r
+   */\r
+  public function get_signature_base_string() {\r
+    $parts = array(\r
+      $this->get_normalized_http_method(),\r
+      $this->get_normalized_http_url(),\r
+      $this->get_signable_parameters()\r
+    );\r
+\r
+    $parts = OAuthUtil::urlencode_rfc3986($parts);\r
+\r
+    return implode('&', $parts);\r
+  }\r
+\r
+  /**\r
+   * just uppercases the http method\r
+   */\r
+  public function get_normalized_http_method() {\r
+    return strtoupper($this->http_method);\r
+  }\r
+\r
+  /**\r
+   * parses the url and rebuilds it to be\r
+   * scheme://host/path\r
+   */\r
+  public function get_normalized_http_url() {\r
+    $parts = parse_url($this->http_url);\r
+\r
+    $port = @$parts['port'];\r
+    $scheme = $parts['scheme'];\r
+    $host = $parts['host'];\r
+    $path = @$parts['path'];\r
+\r
+    $port or $port = ($scheme == 'https') ? '443' : '80';\r
+\r
+    if (($scheme == 'https' && $port != '443')\r
+        || ($scheme == 'http' && $port != '80')) {\r
+      $host = "$host:$port";\r
+    }\r
+    return "$scheme://$host$path";\r
+  }\r
+\r
+  /**\r
+   * builds a url usable for a GET request\r
+   */\r
+  public function to_url() {\r
+    $post_data = $this->to_postdata();\r
+    $out = $this->get_normalized_http_url();\r
+    if ($post_data) {\r
+      $out .= '?'.$post_data;\r
+    }\r
+    return $out;\r
+  }\r
+\r
+  /**\r
+   * builds the data one would send in a POST request\r
+   */\r
+  public function to_postdata() {\r
+    return OAuthUtil::build_http_query($this->parameters);\r
+  }\r
+\r
+  /**\r
+   * builds the Authorization: header\r
+   */\r
+  public function to_header($realm=null) {\r
+    $first = true;\r
+       if($realm) {\r
+      $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"';\r
+      $first = false;\r
+    } else\r
+      $out = 'Authorization: OAuth';\r
+\r
+    $total = array();\r
+    foreach ($this->parameters as $k => $v) {\r
+      if (substr($k, 0, 5) != "oauth") continue;\r
+      if (is_array($v)) {\r
+        throw new OAuthException('Arrays not supported in headers');\r
+      }\r
+      $out .= ($first) ? ' ' : ',';\r
+      $out .= OAuthUtil::urlencode_rfc3986($k) .\r
+              '="' .\r
+              OAuthUtil::urlencode_rfc3986($v) .\r
+              '"';\r
+      $first = false;\r
+    }\r
+    return $out;\r
+  }\r
+\r
+  public function __toString() {\r
+    return $this->to_url();\r
+  }\r
+\r
+\r
+  public function sign_request($signature_method, $consumer, $token) {\r
+    $this->set_parameter(\r
+      "oauth_signature_method",\r
+      $signature_method->get_name(),\r
+      false\r
+    );\r
+    $signature = $this->build_signature($signature_method, $consumer, $token);\r
+    $this->set_parameter("oauth_signature", $signature, false);\r
+  }\r
+\r
+  public function build_signature($signature_method, $consumer, $token) {\r
+    $signature = $signature_method->build_signature($this, $consumer, $token);\r
+    return $signature;\r
+  }\r
+\r
+  /**\r
+   * util function: current timestamp\r
+   */\r
+  private static function generate_timestamp() {\r
+    return time();\r
+  }\r
+\r
+  /**\r
+   * util function: current nonce\r
+   */\r
+  private static function generate_nonce() {\r
+    $mt = microtime();\r
+    $rand = mt_rand();\r
+\r
+    return md5($mt . $rand); // md5s look nicer than numbers\r
+  }\r
+}\r
+\r
+class OAuthServer {\r
+  protected $timestamp_threshold = 300; // in seconds, five minutes\r
+  protected $version = '1.0';             // hi blaine\r
+  protected $signature_methods = array();\r
+\r
+  protected $data_store;\r
+\r
+  function __construct($data_store) {\r
+    $this->data_store = $data_store;\r
+  }\r
+\r
+  public function add_signature_method($signature_method) {\r
+    $this->signature_methods[$signature_method->get_name()] =\r
+      $signature_method;\r
+  }\r
+\r
+  // high level functions\r
+\r
+  /**\r
+   * process a request_token request\r
+   * returns the request token on success\r
+   */\r
+  public function fetch_request_token(&$request) {\r
+    $this->get_version($request);\r
+\r
+    $consumer = $this->get_consumer($request);\r
+\r
+    // no token required for the initial token request\r
+    $token = NULL;\r
+\r
+    $this->check_signature($request, $consumer, $token);\r
+\r
+    // Rev A change\r
+    $callback = $request->get_parameter('oauth_callback');\r
+    $new_token = $this->data_store->new_request_token($consumer, $callback);\r
+\r
+    return $new_token;\r
+  }\r
+\r
+  /**\r
+   * process an access_token request\r
+   * returns the access token on success\r
+   */\r
+  public function fetch_access_token(&$request) {\r
+    $this->get_version($request);\r
+\r
+    $consumer = $this->get_consumer($request);\r
+\r
+    // requires authorized request token\r
+    $token = $this->get_token($request, $consumer, "request");\r
+\r
+    $this->check_signature($request, $consumer, $token);\r
+\r
+    // Rev A change\r
+    $verifier = $request->get_parameter('oauth_verifier');\r
+    $new_token = $this->data_store->new_access_token($token, $consumer, $verifier);\r
+\r
+    return $new_token;\r
+  }\r
+\r
+  /**\r
+   * verify an api call, checks all the parameters\r
+   */\r
+  public function verify_request(&$request) {\r
+    $this->get_version($request);\r
+    $consumer = $this->get_consumer($request);\r
+    $token = $this->get_token($request, $consumer, "access");\r
+    $this->check_signature($request, $consumer, $token);\r
+    return array($consumer, $token);\r
+  }\r
+\r
+  // Internals from here\r
+  /**\r
+   * version 1\r
+   */\r
+  private function get_version(&$request) {\r
+    $version = $request->get_parameter("oauth_version");\r
+    if (!$version) {\r
+      // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present. \r
+      // Chapter 7.0 ("Accessing Protected Ressources")\r
+      $version = '1.0';\r
+    }\r
+    if ($version !== $this->version) {\r
+      throw new OAuthException("OAuth version '$version' not supported");\r
+    }\r
+    return $version;\r
+  }\r
+\r
+  /**\r
+   * figure out the signature with some defaults\r
+   */\r
+  private function get_signature_method(&$request) {\r
+    $signature_method =\r
+        @$request->get_parameter("oauth_signature_method");\r
+\r
+    if (!$signature_method) {\r
+      // According to chapter 7 ("Accessing Protected Ressources") the signature-method\r
+      // parameter is required, and we can't just fallback to PLAINTEXT\r
+      throw new OAuthException('No signature method parameter. This parameter is required');\r
+    }\r
+\r
+    if (!in_array($signature_method,\r
+                  array_keys($this->signature_methods))) {\r
+      throw new OAuthException(\r
+        "Signature method '$signature_method' not supported " .\r
+        "try one of the following: " .\r
+        implode(", ", array_keys($this->signature_methods))\r
+      );\r
+    }\r
+    return $this->signature_methods[$signature_method];\r
+  }\r
+\r
+  /**\r
+   * try to find the consumer for the provided request's consumer key\r
+   */\r
+  private function get_consumer(&$request) {\r
+    $consumer_key = @$request->get_parameter("oauth_consumer_key");\r
+    if (!$consumer_key) {\r
+      throw new OAuthException("Invalid consumer key");\r
+    }\r
+\r
+    $consumer = $this->data_store->lookup_consumer($consumer_key);\r
+    if (!$consumer) {\r
+      throw new OAuthException("Invalid consumer");\r
+    }\r
+\r
+    return $consumer;\r
+  }\r
+\r
+  /**\r
+   * try to find the token for the provided request's token key\r
+   */\r
+  private function get_token(&$request, $consumer, $token_type="access") {\r
+    $token_field = @$request->get_parameter('oauth_token');\r
+    $token = $this->data_store->lookup_token(\r
+      $consumer, $token_type, $token_field\r
+    );\r
+    if (!$token) {\r
+      throw new OAuthException("Invalid $token_type token: $token_field");\r
+    }\r
+    return $token;\r
+  }\r
+\r
+  /**\r
+   * all-in-one function to check the signature on a request\r
+   * should guess the signature method appropriately\r
+   */\r
+  private function check_signature(&$request, $consumer, $token) {\r
+    // this should probably be in a different method\r
+    $timestamp = @$request->get_parameter('oauth_timestamp');\r
+    $nonce = @$request->get_parameter('oauth_nonce');\r
+\r
+    $this->check_timestamp($timestamp);\r
+    $this->check_nonce($consumer, $token, $nonce, $timestamp);\r
+\r
+    $signature_method = $this->get_signature_method($request);\r
+\r
+    $signature = $request->get_parameter('oauth_signature');\r
+    $valid_sig = $signature_method->check_signature(\r
+      $request,\r
+      $consumer,\r
+      $token,\r
+      $signature\r
+    );\r
+\r
+    if (!$valid_sig) {\r
+      throw new OAuthException("Invalid signature");\r
+    }\r
+  }\r
+\r
+  /**\r
+   * check that the timestamp is new enough\r
+   */\r
+  private function check_timestamp($timestamp) {\r
+    if( ! $timestamp )\r
+      throw new OAuthException(\r
+        'Missing timestamp parameter. The parameter is required'\r
+      );\r
+    \r
+    // verify that timestamp is recentish\r
+    $now = time();\r
+    if (abs($now - $timestamp) > $this->timestamp_threshold) {\r
+      throw new OAuthException(\r
+        "Expired timestamp, yours $timestamp, ours $now"\r
+      );\r
+    }\r
+  }\r
+\r
+  /**\r
+   * check that the nonce is not repeated\r
+   */\r
+  private function check_nonce($consumer, $token, $nonce, $timestamp) {\r
+    if( ! $nonce )\r
+      throw new OAuthException(\r
+        'Missing nonce parameter. The parameter is required'\r
+      );\r
+\r
+    // verify that the nonce is uniqueish\r
+    $found = $this->data_store->lookup_nonce(\r
+      $consumer,\r
+      $token,\r
+      $nonce,\r
+      $timestamp\r
+    );\r
+    if ($found) {\r
+      throw new OAuthException("Nonce already used: $nonce");\r
+    }\r
+  }\r
+\r
+}\r
+\r
+class OAuthDataStore {\r
+  function lookup_consumer($consumer_key) {\r
+    // implement me\r
+  }\r
+\r
+  function lookup_token($consumer, $token_type, $token) {\r
+    // implement me\r
+  }\r
+\r
+  function lookup_nonce($consumer, $token, $nonce, $timestamp) {\r
+    // implement me\r
+  }\r
+\r
+  function new_request_token($consumer, $callback = null) {\r
+    // return a new token attached to this consumer\r
+  }\r
+\r
+  function new_access_token($token, $consumer, $verifier = null) {\r
+    // return a new access token attached to this consumer\r
+    // for the user associated with this token if the request token\r
+    // is authorized\r
+    // should also invalidate the request token\r
+  }\r
+\r
+}\r
+\r
+class OAuthUtil {\r
+  public static function urlencode_rfc3986($input) {\r
+  if (is_array($input)) {\r
+    return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input);\r
+  } else if (is_scalar($input)) {\r
+    return str_replace(\r
+      '+',\r
+      ' ',\r
+      str_replace('%7E', '~', rawurlencode($input))\r
+    );\r
+  } else {\r
+    return '';\r
+  }\r
+}\r
+\r
+\r
+  // This decode function isn't taking into consideration the above\r
+  // modifications to the encoding process. However, this method doesn't\r
+  // seem to be used anywhere so leaving it as is.\r
+  public static function urldecode_rfc3986($string) {\r
+    return urldecode($string);\r
+  }\r
+\r
+  // Utility function for turning the Authorization: header into\r
+  // parameters, has to do some unescaping\r
+  // Can filter out any non-oauth parameters if needed (default behaviour)\r
+  public static function split_header($header, $only_allow_oauth_parameters = true) {\r
+    $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';\r
+    $offset = 0;\r
+    $params = array();\r
+    while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {\r
+      $match = $matches[0];\r
+      $header_name = $matches[2][0];\r
+      $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0];\r
+      if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) {\r
+        $params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content);\r
+      }\r
+      $offset = $match[1] + strlen($match[0]);\r
+    }\r
+\r
+    if (isset($params['realm'])) {\r
+      unset($params['realm']);\r
+    }\r
+\r
+    return $params;\r
+  }\r
+\r
+  // helper to try to sort out headers for people who aren't running apache\r
+  public static function get_headers() {\r
+    if (function_exists('apache_request_headers')) {\r
+      // we need this to get the actual Authorization: header\r
+      // because apache tends to tell us it doesn't exist\r
+      $headers = apache_request_headers();\r
+\r
+      // sanitize the output of apache_request_headers because\r
+      // we always want the keys to be Cased-Like-This and arh()\r
+      // returns the headers in the same case as they are in the\r
+      // request\r
+      $out = array();\r
+      foreach( $headers AS $key => $value ) {\r
+        $key = str_replace(\r
+            " ",\r
+            "-",\r
+            ucwords(strtolower(str_replace("-", " ", $key)))\r
+          );\r
+        $out[$key] = $value;\r
+      }\r
+    } else {\r
+      // otherwise we don't have apache and are just going to have to hope\r
+      // that $_SERVER actually contains what we need\r
+      $out = array();\r
+      if( isset($_SERVER['CONTENT_TYPE']) )\r
+        $out['Content-Type'] = $_SERVER['CONTENT_TYPE'];\r
+      if( isset($_ENV['CONTENT_TYPE']) )\r
+        $out['Content-Type'] = $_ENV['CONTENT_TYPE'];\r
+\r
+      foreach ($_SERVER as $key => $value) {\r
+        if (substr($key, 0, 5) == "HTTP_") {\r
+          // this is chaos, basically it is just there to capitalize the first\r
+          // letter of every word that is not an initial HTTP and strip HTTP\r
+          // code from przemek\r
+          $key = str_replace(\r
+            " ",\r
+            "-",\r
+            ucwords(strtolower(str_replace("_", " ", substr($key, 5))))\r
+          );\r
+          $out[$key] = $value;\r
+        }\r
+      }\r
+    }\r
+    return $out;\r
+  }\r
+\r
+  // This function takes a input like a=b&a=c&d=e and returns the parsed\r
+  // parameters like this\r
+  // array('a' => array('b','c'), 'd' => 'e')\r
+  public static function parse_parameters( $input ) {\r
+    if (!isset($input) || !$input) return array();\r
+\r
+    $pairs = explode('&', $input);\r
+\r
+    $parsed_parameters = array();\r
+    foreach ($pairs as $pair) {\r
+      $split = explode('=', $pair, 2);\r
+      $parameter = OAuthUtil::urldecode_rfc3986($split[0]);\r
+      $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : '';\r
+\r
+      if (isset($parsed_parameters[$parameter])) {\r
+        // We have already recieved parameter(s) with this name, so add to the list\r
+        // of parameters with this name\r
+\r
+        if (is_scalar($parsed_parameters[$parameter])) {\r
+          // This is the first duplicate, so transform scalar (string) into an array\r
+          // so we can add the duplicates\r
+          $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);\r
+        }\r
+\r
+        $parsed_parameters[$parameter][] = $value;\r
+      } else {\r
+        $parsed_parameters[$parameter] = $value;\r
+      }\r
+    }\r
+    return $parsed_parameters;\r
+  }\r
+\r
+  public static function build_http_query($params) {\r
+    if (!$params) return '';\r
+\r
+    // Urlencode both keys and values\r
+    $keys = OAuthUtil::urlencode_rfc3986(array_keys($params));\r
+    $values = OAuthUtil::urlencode_rfc3986(array_values($params));\r
+    $params = array_combine($keys, $values);\r
+\r
+    // Parameters are sorted by name, using lexicographical byte value ordering.\r
+    // Ref: Spec: 9.1.1 (1)\r
+    uksort($params, 'strcmp');\r
+\r
+    $pairs = array();\r
+    foreach ($params as $parameter => $value) {\r
+      if (is_array($value)) {\r
+        // If two or more parameters share the same name, they are sorted by their value\r
+        // Ref: Spec: 9.1.1 (1)\r
+        natsort($value);\r
+        foreach ($value as $duplicate_value) {\r
+          $pairs[] = $parameter . '=' . $duplicate_value;\r
+        }\r
+      } else {\r
+        $pairs[] = $parameter . '=' . $value;\r
+      }\r
+    }\r
+    // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)\r
+    // Each name-value pair is separated by an '&' character (ASCII code 38)\r
+    return implode('&', $pairs);\r
+  }\r
+}\r
+\r
+?>\r
diff --git a/tumblr/tumblroauth/tumblroauth.php b/tumblr/tumblroauth/tumblroauth.php
new file mode 100644 (file)
index 0000000..3c6f13c
--- /dev/null
@@ -0,0 +1,245 @@
+<?php\r
+\r
+/*\r
+ * Abraham Williams (abraham@abrah.am) http://abrah.am\r
+ *\r
+ * The first PHP Library to support OAuth for Tumblr's REST API.  (Originally for Twitter, modified for Tumblr by Lucas)\r
+ */\r
+\r
+/* Load OAuth lib. You can find it at http://oauth.net */\r
+//require_once('OAuth.php');\r
+\r
+/**\r
+ * Tumblr OAuth class\r
+ */\r
+class TumblrOAuth {\r
+  /* Contains the last HTTP status code returned. */\r
+  public $http_code;\r
+  /* Contains the last API call. */\r
+  public $url;\r
+  /* Set up the API root URL. */\r
+  public $host = "http://api.tumblr.com/v2/";\r
+  /* Set timeout default. */\r
+  public $timeout = 30;\r
+  /* Set connect timeout. */\r
+  public $connecttimeout = 30; \r
+  /* Verify SSL Cert. */\r
+  public $ssl_verifypeer = FALSE;\r
+  /* Respons format. */\r
+  public $format = 'json';\r
+  /* Decode returned json data. */\r
+  public $decode_json = TRUE;\r
+  /* Contains the last HTTP headers returned. */\r
+  public $http_info;\r
+  /* Set the useragnet. */\r
+  public $useragent = 'TumblrOAuth v0.2.0-beta2';\r
+  /* Immediately retry the API call if the response was not successful. */\r
+  //public $retry = TRUE;\r
+\r
+\r
+\r
+\r
+  /**\r
+   * Set API URLS\r
+   */\r
+  function accessTokenURL()  { return 'http://www.tumblr.com/oauth/access_token'; }\r
+  function authenticateURL() { return 'http://www.tumblr.com/oauth/authorize'; }\r
+  function authorizeURL()    { return 'http://www.tumblr.com/oauth/authorize'; }\r
+  function requestTokenURL() { return 'http://www.tumblr.com/oauth/request_token'; }\r
+\r
+  /**\r
+   * Debug helpers\r
+   */\r
+  function lastStatusCode() { return $this->http_status; }\r
+  function lastAPICall() { return $this->last_api_call; }\r
+\r
+  /**\r
+   * construct TumblrOAuth object\r
+   */\r
+  function __construct($consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) {\r
+    $this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1();\r
+    $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret);\r
+    if (!empty($oauth_token) && !empty($oauth_token_secret)) {\r
+      $this->token = new OAuthConsumer($oauth_token, $oauth_token_secret);\r
+    } else {\r
+      $this->token = NULL;\r
+    }\r
+  }\r
+\r
+\r
+  /**\r
+   * Get a request_token from Tumblr\r
+   *\r
+   * @returns a key/value array containing oauth_token and oauth_token_secret\r
+   */\r
+  function getRequestToken($oauth_callback = NULL) {\r
+    $parameters = array();\r
+    if (!empty($oauth_callback)) {\r
+      $parameters['oauth_callback'] = $oauth_callback;\r
+    } \r
+    $request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters);\r
+    $token = OAuthUtil::parse_parameters($request);\r
+    $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);\r
+    return $token;\r
+  }\r
+\r
+  /**\r
+   * Get the authorize URL\r
+   *\r
+   * @returns a string\r
+   */\r
+  function getAuthorizeURL($token, $sign_in_with_tumblr = TRUE) {\r
+    if (is_array($token)) {\r
+      $token = $token['oauth_token'];\r
+    }\r
+    if (empty($sign_in_with_tumblr)) {\r
+      return $this->authorizeURL() . "?oauth_token={$token}";\r
+    } else {\r
+       return $this->authenticateURL() . "?oauth_token={$token}";\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Exchange request token and secret for an access token and\r
+   * secret, to sign API calls.\r
+   *\r
+   * @returns array("oauth_token" => "the-access-token",\r
+   *                "oauth_token_secret" => "the-access-secret",\r
+   *                "user_id" => "9436992",\r
+   *                "screen_name" => "abraham")\r
+   */\r
+  function getAccessToken($oauth_verifier = FALSE) {\r
+    $parameters = array();\r
+    if (!empty($oauth_verifier)) {\r
+      $parameters['oauth_verifier'] = $oauth_verifier;\r
+    }\r
+    $request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters);\r
+    $token = OAuthUtil::parse_parameters($request);\r
+    $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);\r
+    return $token;\r
+  }\r
+\r
+  /**\r
+   * One time exchange of username and password for access token and secret.\r
+   *\r
+   * @returns array("oauth_token" => "the-access-token",\r
+   *                "oauth_token_secret" => "the-access-secret",\r
+   *                "user_id" => "9436992",\r
+   *                "screen_name" => "abraham",\r
+   *                "x_auth_expires" => "0")\r
+   */  \r
+  function getXAuthToken($username, $password) {\r
+    $parameters = array();\r
+    $parameters['x_auth_username'] = $username;\r
+    $parameters['x_auth_password'] = $password;\r
+    $parameters['x_auth_mode'] = 'client_auth';\r
+    $request = $this->oAuthRequest($this->accessTokenURL(), 'POST', $parameters);\r
+    $token = OAuthUtil::parse_parameters($request);\r
+    $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);\r
+    return $token;\r
+  }\r
+\r
+  /**\r
+   * GET wrapper for oAuthRequest.\r
+   */\r
+  function get($url, $parameters = array()) {\r
+    $response = $this->oAuthRequest($url, 'GET', $parameters);\r
+    if ($this->format === 'json' && $this->decode_json) {\r
+      return json_decode($response);\r
+    }\r
+    return $response;\r
+  }\r
+  \r
+  /**\r
+   * POST wrapper for oAuthRequest.\r
+   */\r
+  function post($url, $parameters = array()) {\r
+    $response = $this->oAuthRequest($url, 'POST', $parameters);\r
+    if ($this->format === 'json' && $this->decode_json) {\r
+      return json_decode($response);\r
+    }\r
+    return $response;\r
+  }\r
+\r
+  /**\r
+   * DELETE wrapper for oAuthReqeust.\r
+   */\r
+  function delete($url, $parameters = array()) {\r
+    $response = $this->oAuthRequest($url, 'DELETE', $parameters);\r
+    if ($this->format === 'json' && $this->decode_json) {\r
+      return json_decode($response);\r
+    }\r
+    return $response;\r
+  }\r
+\r
+  /**\r
+   * Format and sign an OAuth / API request\r
+   */\r
+  function oAuthRequest($url, $method, $parameters) {\r
+    if (strrpos($url, 'https://') !== 0 && strrpos($url, 'http://') !== 0) {\r
+      $url = "{$this->host}{$url}";\r
+    }\r
+    $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $parameters);\r
+    $request->sign_request($this->sha1_method, $this->consumer, $this->token);\r
+    switch ($method) {\r
+    case 'GET':\r
+      return $this->http($request->to_url(), 'GET');\r
+    default:\r
+      return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata());\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Make an HTTP request\r
+   *\r
+   * @return API results\r
+   */\r
+  function http($url, $method, $postfields = NULL) {\r
+    $this->http_info = array();\r
+    $ci = curl_init();\r
+    /* Curl settings */\r
+    curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);\r
+    curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);\r
+    curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);\r
+    curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);\r
+    curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:'));\r
+    curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);\r
+    curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));\r
+    curl_setopt($ci, CURLOPT_HEADER, FALSE);\r
+\r
+    switch ($method) {\r
+      case 'POST':\r
+        curl_setopt($ci, CURLOPT_POST, TRUE);\r
+        if (!empty($postfields)) {\r
+          curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);\r
+        }\r
+        break;\r
+      case 'DELETE':\r
+        curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');\r
+        if (!empty($postfields)) {\r
+          $url = "{$url}?{$postfields}";\r
+        }\r
+    }\r
+\r
+    curl_setopt($ci, CURLOPT_URL, $url);\r
+    $response = curl_exec($ci);\r
+    $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);\r
+    $this->http_info = array_merge($this->http_info, curl_getinfo($ci));\r
+    $this->url = $url;\r
+    curl_close ($ci);\r
+    return $response;\r
+  }\r
+\r
+  /**\r
+   * Get the header info to store.\r
+   */\r
+  function getHeader($ch, $header) {\r
+    $i = strpos($header, ':');\r
+    if (!empty($i)) {\r
+      $key = str_replace('-', '_', strtolower(substr($header, 0, $i)));\r
+      $value = trim(substr($header, $i + 2));\r
+      $this->http_header[$key] = $value;\r
+    }\r
+    return strlen($header);\r
+  }\r
+}\r
index beeea2bee46fb21069de6b6402035d4e3bf71511..7558bca9d37cc7448a90ff2173ea8a24561da0e6 100755 (executable)
Binary files a/twitter.tgz and b/twitter.tgz differ
index ff08976c79613d98828d078c0b603c1c1f25158b..8041f317be8582ffa39a8adb8f1ae41c2bbd99eb 100755 (executable)
@@ -3,17 +3,14 @@ By Tobias Diekershoff
    http://diekershoff.homeunix.net/friendika/profile/tobias
    tobias.diekershoff(at)gmx.net
 
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!!   This addon is currently under development. If you have any problem     !!
-!!   with it, please contact the Author.                                    !!
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
 With this addon to Friendica you can give your user the possibility to post
 their *public* messages to Twitter. The messages will be strapped their rich
 context and shortened to 140 characters length if necessary. If shortening of
 the message was performed a link will be added to the Tweet pointing to the
 original message on your server.
 
+The addon can also mirror a users Tweets into the ~friendica wall.
+
 There is a similar addon for forwarding public messages to
 "StatusNet":http://status.net [[StatusNet Plugin]].
 
diff --git a/twitter/admin.tpl b/twitter/admin.tpl
deleted file mode 100755 (executable)
index a83eb07..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-{{ inc field_input.tpl with $field=$consumerkey }}{{ endinc }}
-{{ inc field_input.tpl with $field=$consumersecret }}{{ endinc }}
-<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
index 75747979eb952a9c07b442ea8d5e330cee0912e5..3ff37cda4a1d0bbfd2fdfece7a3b397172c52907 100755 (executable)
 #twitter-disconnect {
        float: left;
 }
-#twitter-enable-label {
-       float: left;
-       width: 250px;
-       margin-bottom: 5px;
-}
-#twitter-default-label {
-       float: left;
-       width: 250px;
-}
-#twitter-sendtaglinks-label {
+#twitter-default-label,
+#twitter-sendtaglinks-label,
+#twitter-enable-label,
+#twitter-shortening-label, 
+#twitter-mirror-label,
+#twitter-pin-label {
         float: left;
         width: 250px;
-        margin-bottom: 25px;
+        margin-bottom: 10px;
 }
 
 #twitter-checkbox {
        float: left;
 }
-#twitter-pin-label {
-       float: left;
-       width: 250px;
-       margin-bottom: 25px;
-}
 
 #twitter-pin {
        float: left;
index 5fd053fa7f95d7b1b09e66bd363fd04ad274dcfe..e4848f9db8122cb63f0878477c55246c340da945 100755 (executable)
@@ -36,6 +36,8 @@
  *     Documentation: http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/Twitter_Plugin
  */
 
+define('TWITTER_DEFAULT_POLL_INTERVAL', 5); // given in minutes
+
 function twitter_install() {
        //  we need some hooks, for the configuration and for sending tweets
        register_hook('connector_settings', 'addon/twitter/twitter.php', 'twitter_settings'); 
@@ -43,6 +45,7 @@ function twitter_install() {
        register_hook('post_local', 'addon/twitter/twitter.php', 'twitter_post_local');
        register_hook('notifier_normal', 'addon/twitter/twitter.php', 'twitter_post_hook');
        register_hook('jot_networks', 'addon/twitter/twitter.php', 'twitter_jot_nets');
+       register_hook('cron', 'addon/twitter/twitter.php', 'twitter_cron');
        logger("installed twitter");
 }
 
@@ -53,6 +56,7 @@ function twitter_uninstall() {
        unregister_hook('post_local', 'addon/twitter/twitter.php', 'twitter_post_local');
        unregister_hook('notifier_normal', 'addon/twitter/twitter.php', 'twitter_post_hook');
        unregister_hook('jot_networks', 'addon/twitter/twitter.php', 'twitter_jot_nets');
+       unregister_hook('cron', 'addon/twitter/twitter.php', 'twitter_cron');
 
        // old setting - remove only
        unregister_hook('post_local_end', 'addon/twitter/twitter.php', 'twitter_post_hook');
@@ -70,10 +74,8 @@ function twitter_jot_nets(&$a,&$b) {
                $tw_defpost = get_pconfig(local_user(),'twitter','post_by_default');
                $selected = ((intval($tw_defpost) == 1) ? ' checked="checked" ' : '');
                $b .= '<div class="profile-jot-net"><input type="checkbox" name="twitter_enable"' . $selected . ' value="1" /> ' 
-                       . t('Post to Twitter') . '</div>';      
+                       . t('Post to Twitter') . '</div>';
        }
-
-
 }
 
 function twitter_settings_post ($a,$post) {
@@ -87,20 +89,23 @@ function twitter_settings_post ($a,$post) {
                 * if the twitter-disconnect checkbox is set, clear the OAuth key/secret pair
                 * from the user configuration
                 */
-               del_pconfig( local_user(), 'twitter', 'consumerkey'  );
-               del_pconfig( local_user(), 'twitter', 'consumersecret' );
-                del_pconfig( local_user(), 'twitter', 'oauthtoken'  );  
-                del_pconfig( local_user(), 'twitter', 'oauthsecret'  );  
-                del_pconfig( local_user(), 'twitter', 'post' );
-                del_pconfig( local_user(), 'twitter', 'post_by_default' );
-                del_pconfig( local_user(), 'twitter', 'post_taglinks');
+               del_pconfig(local_user(), 'twitter', 'consumerkey');
+               del_pconfig(local_user(), 'twitter', 'consumersecret');
+                del_pconfig(local_user(), 'twitter', 'oauthtoken');
+                del_pconfig(local_user(), 'twitter', 'oauthsecret');
+                del_pconfig(local_user(), 'twitter', 'post');
+                del_pconfig(local_user(), 'twitter', 'post_by_default');
+                del_pconfig(local_user(), 'twitter', 'post_taglinks');
+               del_pconfig(local_user(), 'twitter', 'lastid');
+               del_pconfig(local_user(), 'twitter', 'mirror_posts');
+               del_pconfig(local_user(), 'twitter', 'intelligent_shortening');
        } else {
        if (isset($_POST['twitter-pin'])) {
                //  if the user supplied us with a PIN from Twitter, let the magic of OAuth happen
                logger('got a Twitter PIN');
                require_once('library/twitteroauth.php');
-               $ckey    = get_config('twitter', 'consumerkey'  );
-               $csecret = get_config('twitter', 'consumersecret' );
+               $ckey    = get_config('twitter', 'consumerkey');
+               $csecret = get_config('twitter', 'consumersecret');
                //  the token and secret for which the PIN was generated were hidden in the settings
                //  form as token and token2, we need a new connection to Twitter using these token
                //  and secret to request a Access Token with the PIN
@@ -119,6 +124,8 @@ function twitter_settings_post ($a,$post) {
                set_pconfig(local_user(),'twitter','post',intval($_POST['twitter-enable']));
                 set_pconfig(local_user(),'twitter','post_by_default',intval($_POST['twitter-default']));
                 set_pconfig(local_user(),'twitter','post_taglinks',intval($_POST['twitter-sendtaglinks']));
+               set_pconfig(local_user(), 'twitter', 'mirror_posts', intval($_POST['twitter-mirror']));
+               set_pconfig(local_user(), 'twitter', 'intelligent_shortening', intval($_POST['twitter-shortening']));
                 info( t('Twitter settings updated.') . EOL);
        }}
 }
@@ -141,6 +148,10 @@ function twitter_settings(&$a,&$s) {
        $defchecked = (($defenabled) ? ' checked="checked" ' : '');
         $linksenabled = get_pconfig(local_user(),'twitter','post_taglinks');
         $linkschecked = (($linksenabled) ? ' checked="checked" ' : '');
+        $mirrorenabled = get_pconfig(local_user(),'twitter','mirror_posts');
+        $mirrorchecked = (($mirrorenabled) ? ' checked="checked" ' : '');
+        $shorteningenabled = get_pconfig(local_user(),'twitter','intelligent_shortening');
+        $shorteningchecked = (($shorteningenabled) ? ' checked="checked" ' : '');
 
        $s .= '<div class="settings-block">';
        $s .= '<h3>'. t('Twitter Posting Settings') .'</h3>';
@@ -198,6 +209,15 @@ function twitter_settings(&$a,&$s) {
                         $s .= '<label id="twitter-default-label" for="twitter-default">'. t('Send public postings to Twitter by default') .'</label>';
                         $s .= '<input id="twitter-default" type="checkbox" name="twitter-default" value="1" ' . $defchecked . '/>';
                        $s .= '<div class="clear"></div>';
+
+                        $s .= '<label id="twitter-mirror-label" for="twitter-mirror">'.t('Mirror all posts from twitter that are no replies or retweets').'</label>';
+                        $s .= '<input id="twitter-mirror" type="checkbox" name="twitter-mirror" value="1" '. $mirrorchecked . '/>';
+                       $s .= '<div class="clear"></div>';
+
+                        $s .= '<label id="twitter-shortening-label" for="twitter-shortening">'.t('Shortening method that optimizes the tweet').'</label>';
+                        $s .= '<input id="twitter-shortening" type="checkbox" name="twitter-shortening" value="1" '. $shorteningchecked . '/>';
+                       $s .= '<div class="clear"></div>';
+
                         $s .= '<label id="twitter-sendtaglinks-label" for="twitter-sendtaglinks">'.t('Send linked #-tags and @-names to Twitter').'</label>';
                         $s .= '<input id="twitter-sendtaglinks" type="checkbox" name="twitter-sendtaglinks" value="1" '. $linkschecked . '/>';
                        $s .= '</div><div class="clear"></div>';
@@ -261,6 +281,133 @@ function short_link ($url) {
     return $slinky->short();
 } };
 
+function twitter_shortenmsg($b) {
+       require_once("include/bbcode.php");
+       require_once("include/html2plain.php");
+
+       $max_char = 140;
+
+       // Looking for the first image
+       $image = '';
+       if(preg_match("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/is",$b['body'],$matches))
+               $image = $matches[3];
+
+       if ($image == '')
+               if(preg_match("/\[img\](.*?)\[\/img\]/is",$b['body'],$matches))
+                       $image = $matches[1];
+
+       $multipleimages = (strpos($b['body'], "[img") != strrpos($b['body'], "[img"));
+
+       // When saved into the database the content is sent through htmlspecialchars
+       // That means that we have to decode all image-urls
+       $image = htmlspecialchars_decode($image);
+
+       $body = $b["body"];
+       if ($b["title"] != "")
+               $body = $b["title"]."\n\n".$body;
+
+       if (strpos($body, "[bookmark") !== false) {
+               // splitting the text in two parts:
+               // before and after the bookmark
+               $pos = strpos($body, "[bookmark");
+               $body1 = substr($body, 0, $pos);
+               $body2 = substr($body, $pos);
+
+               // Removing all quotes after the bookmark
+               // they are mostly only the content after the bookmark.
+               $body2 = preg_replace("/\[quote\=([^\]]*)\](.*?)\[\/quote\]/ism",'',$body2);
+               $body2 = preg_replace("/\[quote\](.*?)\[\/quote\]/ism",'',$body2);
+               $body = $body1.$body2;
+       }
+
+       // Add some newlines so that the message could be cut better
+       $body = str_replace(array("[quote", "[bookmark", "[/bookmark]", "[/quote]"),
+                       array("\n[quote", "\n[bookmark", "[/bookmark]\n", "[/quote]\n"), $body);
+
+       // remove the recycle signs and the names since they aren't helpful on twitter
+       // recycle 1
+       $recycle = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8');
+       $body = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', "\n", $body);
+       // recycle 2 (Test)
+       $recycle = html_entity_decode("&#x25CC; ", ENT_QUOTES, 'UTF-8');
+       $body = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', "\n", $body);
+
+       // remove the share element
+       $body = preg_replace("/\[share(.*?)\](.*?)\[\/share\]/ism","\n\n$2\n\n",$body);
+
+       // At first convert the text to html
+       $html = bbcode($body, false, false);
+
+       // Then convert it to plain text
+       //$msg = trim($b['title']." \n\n".html2plain($html, 0, true));
+       $msg = trim(html2plain($html, 0, true));
+       $msg = html_entity_decode($msg,ENT_QUOTES,'UTF-8');
+
+       // Removing multiple newlines
+       while (strpos($msg, "\n\n\n") !== false)
+               $msg = str_replace("\n\n\n", "\n\n", $msg);
+
+       // Removing multiple spaces
+       while (strpos($msg, "  ") !== false)
+               $msg = str_replace("  ", " ", $msg);
+
+       // Removing URLs
+       $msg = preg_replace('/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/i', "", $msg);
+
+       $msg = trim($msg);
+
+       $link = '';
+       // look for bookmark-bbcode and handle it with priority
+       if(preg_match("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/is",$b['body'],$matches))
+               $link = $matches[1];
+
+       $multiplelinks = (strpos($b['body'], "[bookmark") != strrpos($b['body'], "[bookmark"));
+
+       // If there is no bookmark element then take the first link
+       if ($link == '') {
+               $links = collecturls($html);
+               if (sizeof($links) > 0) {
+                       reset($links);
+                       $link = current($links);
+               }
+               $multiplelinks = (sizeof($links) > 1);
+       }
+
+       $msglink = "";
+       if ($multiplelinks)
+               $msglink = $b["plink"];
+       else if ($link != "")
+               $msglink = $link;
+       else if ($multipleimages)
+               $msglink = $b["plink"];
+       else if ($image != "")
+               $msglink = $image;
+
+       if (($msglink == "") and strlen($msg) > $max_char)
+               $msglink = $b["plink"];
+
+       if (strlen($msglink) > 20)
+               $msglink = short_link($msglink);
+
+       if (strlen(trim($msg." ".$msglink)) > $max_char) {
+               $msg = substr($msg, 0, $max_char - (strlen($msglink)));
+               $lastchar = substr($msg, -1);
+               $msg = substr($msg, 0, -1);
+               $pos = strrpos($msg, "\n");
+               if ($pos > 0)
+                       $msg = substr($msg, 0, $pos);
+               else if ($lastchar != "\n")
+                       $msg = substr($msg, 0, -3)."...";
+       }
+       $msg = str_replace("\n", " ", $msg);
+
+       // Removing multiple spaces - again
+       while (strpos($msg, "  ") !== false)
+               $msg = str_replace("  ", " ", $msg);
+
+       return(trim($msg." ".$msglink));
+}
+
 function twitter_post_hook(&$a,&$b) {
 
        /**
@@ -276,15 +423,24 @@ function twitter_post_hook(&$a,&$b) {
        if($b['parent'] != $b['id'])
                return;
 
+       // if post comes from twitter don't send it back
+       if($b['app'] == "Twitter")
+               return;
+
        logger('twitter post invoked');
 
 
        load_pconfig($b['uid'], 'twitter');
 
-       $ckey    = get_config('twitter', 'consumerkey'  );
-       $csecret = get_config('twitter', 'consumersecret' );
-       $otoken  = get_pconfig($b['uid'], 'twitter', 'oauthtoken'  );
-       $osecret = get_pconfig($b['uid'], 'twitter', 'oauthsecret' );
+       $ckey    = get_config('twitter', 'consumerkey');
+       $csecret = get_config('twitter', 'consumersecret');
+       $otoken  = get_pconfig($b['uid'], 'twitter', 'oauthtoken');
+       $osecret = get_pconfig($b['uid'], 'twitter', 'oauthsecret');
+       $intelligent_shortening = get_pconfig($b['uid'], 'twitter', 'intelligent_shortening');
+
+       // Global setting overrides this
+       if (get_config('twitter','intelligent_shortening'))
+                $intelligent_shortening = get_config('twitter','intelligent_shortening');
 
        if($ckey && $csecret && $otoken && $osecret) {
                logger('twitter: we have customer key and oauth stuff, going to send.', LOGGER_DEBUG);
@@ -294,81 +450,84 @@ function twitter_post_hook(&$a,&$b) {
                $tweet = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
                 // in theory max char is 140 but T. uses t.co to make links 
                 // longer so we give them 10 characters extra
-               $max_char = 130; // max. length for a tweet
-                // we will only work with up to two times the length of the dent 
-                // we can later send to Twitter. This way we can "gain" some 
-                // information during shortening of potential links but do not 
-                // shorten all the links in a 200000 character long essay.
-                if (! $b['title']=='') {
-                    $tmp = $b['title'] . ' : '. $b['body'];
-//                    $tmp = substr($tmp, 0, 4*$max_char);
-                } else {
-                    $tmp = $b['body']; // substr($b['body'], 0, 3*$max_char);
-                }
-                // if [url=bla][img]blub.png[/img][/url] get blub.png
-                $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\]\[img\](\\w+.*?)\\[\\/img\]\\[\\/url\]/i', '$2', $tmp);
-                // preserve links to images, videos and audios
-                $tmp = preg_replace( '/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism', '$3', $tmp);
-                $tmp = preg_replace( '/\[\\/?img(\\s+.*?\]|\])/i', '', $tmp);
-                $tmp = preg_replace( '/\[\\/?video(\\s+.*?\]|\])/i', '', $tmp);
-                $tmp = preg_replace( '/\[\\/?youtube(\\s+.*?\]|\])/i', '', $tmp);
-                $tmp = preg_replace( '/\[\\/?vimeo(\\s+.*?\]|\])/i', '', $tmp);
-                $tmp = preg_replace( '/\[\\/?audio(\\s+.*?\]|\])/i', '', $tmp);
-                $linksenabled = get_pconfig($b['uid'],'twitter','post_taglinks');
-                // if a #tag is linked, don't send the [url] over to SN
-                // that is, don't send if the option is not set in the
-                // connector settings
-                if ($linksenabled=='0') {
-                       // #-tags
-                       $tmp = preg_replace( '/#\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '#$2', $tmp);
-                       // @-mentions
-                       $tmp = preg_replace( '/@\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '@$2', $tmp);
-                       // recycle 1
-                       $recycle = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8');
-                       $tmp = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', $recycle.'$2', $tmp);
-                       // recycle 2 (Test)
-                       $recycle = html_entity_decode("&#x25CC; ", ENT_QUOTES, 'UTF-8');
-                       $tmp = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', $recycle.'$2', $tmp);
-                }
-                $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\](\w+.*?)\[\/url\]/i', '$2 $1', $tmp);
-                $tmp = preg_replace( '/\[bookmark\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\](\w+.*?)\[\/bookmark\]/i', '$2 $1', $tmp);
-                // find all http or https links in the body of the entry and
-                // apply the shortener if the link is longer then 20 characters
-                if (( strlen($tmp)>$max_char ) && ( $max_char > 0 )) {
-                    preg_match_all ( '/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/i', $tmp, $allurls  );
-                    foreach ($allurls as $url) {
-                        foreach ($url as $u) {
-                            if (strlen($u)>20) {
-                                $sl = short_link($u);
-                                $tmp = str_replace( $u, $sl, $tmp );
-                            }
-                        }
-                    }
-                }
-                // ok, all the links we want to send out are save, now strip 
-                // away the remaining bbcode
-               //$msg = strip_tags(bbcode($tmp, false, false));
-               $msg = bbcode($tmp, false, false);
-               $msg = str_replace(array('<br>','<br />'),"\n",$msg);
-               $msg = strip_tags($msg);
-
-               // quotes not working - let's try this
-               $msg = html_entity_decode($msg);
-               if (( strlen($msg) > $max_char) && $max_char > 0) {
-                       $shortlink = short_link( $b['plink'] );
-                       // the new message will be shortened such that "... $shortlink"
-                       // will fit into the character limit
-                       $msg = nl2br(substr($msg, 0, $max_char-strlen($shortlink)-4));
-                        $msg = str_replace(array('<br>','<br />'),' ',$msg);
-                        $e = explode(' ', $msg);
-                        //  remove the last word from the cut down message to 
-                        //  avoid sending cut words to the MicroBlog
-                        array_pop($e);
-                        $msg = implode(' ', $e);
-                       $msg .= '... ' . $shortlink;
-               }
+               if (!$intelligent_shortening) {
+                       $max_char = 130; // max. length for a tweet
+                       // we will only work with up to two times the length of the dent 
+                       // we can later send to Twitter. This way we can "gain" some 
+                       // information during shortening of potential links but do not 
+                       // shorten all the links in a 200000 character long essay.
+                       if (! $b['title']=='') {
+                           $tmp = $b['title'] . ' : '. $b['body'];
+       //                    $tmp = substr($tmp, 0, 4*$max_char);
+                       } else {
+                           $tmp = $b['body']; // substr($b['body'], 0, 3*$max_char);
+                       }
+                       // if [url=bla][img]blub.png[/img][/url] get blub.png
+                       $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\]\[img\](\\w+.*?)\\[\\/img\]\\[\\/url\]/i', '$2', $tmp);
+                       // preserve links to images, videos and audios
+                       $tmp = preg_replace( '/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism', '$3', $tmp);
+                       $tmp = preg_replace( '/\[\\/?img(\\s+.*?\]|\])/i', '', $tmp);
+                       $tmp = preg_replace( '/\[\\/?video(\\s+.*?\]|\])/i', '', $tmp);
+                       $tmp = preg_replace( '/\[\\/?youtube(\\s+.*?\]|\])/i', '', $tmp);
+                       $tmp = preg_replace( '/\[\\/?vimeo(\\s+.*?\]|\])/i', '', $tmp);
+                       $tmp = preg_replace( '/\[\\/?audio(\\s+.*?\]|\])/i', '', $tmp);
+                       $linksenabled = get_pconfig($b['uid'],'twitter','post_taglinks');
+                       // if a #tag is linked, don't send the [url] over to SN
+                       // that is, don't send if the option is not set in the
+                       // connector settings
+                       if ($linksenabled=='0') {
+                               // #-tags
+                               $tmp = preg_replace( '/#\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '#$2', $tmp);
+                               // @-mentions
+                               $tmp = preg_replace( '/@\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '@$2', $tmp);
+                               // recycle 1
+                               $recycle = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8');
+                               $tmp = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', $recycle.'$2', $tmp);
+                               // recycle 2 (Test)
+                               $recycle = html_entity_decode("&#x25CC; ", ENT_QUOTES, 'UTF-8');
+                               $tmp = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', $recycle.'$2', $tmp);
+                       }
+                       $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\](\w+.*?)\[\/url\]/i', '$2 $1', $tmp);
+                       $tmp = preg_replace( '/\[bookmark\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\](\w+.*?)\[\/bookmark\]/i', '$2 $1', $tmp);
+                       // find all http or https links in the body of the entry and
+                       // apply the shortener if the link is longer then 20 characters
+                       if (( strlen($tmp)>$max_char ) && ( $max_char > 0 )) {
+                           preg_match_all ( '/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/i', $tmp, $allurls  );
+                           foreach ($allurls as $url) {
+                               foreach ($url as $u) {
+                                   if (strlen($u)>20) {
+                                       $sl = short_link($u);
+                                       $tmp = str_replace( $u, $sl, $tmp );
+                                   }
+                               }
+                           }
+                       }
+                       // ok, all the links we want to send out are save, now strip 
+                       // away the remaining bbcode
+                       //$msg = strip_tags(bbcode($tmp, false, false));
+                       $msg = bbcode($tmp, false, false);
+                       $msg = str_replace(array('<br>','<br />'),"\n",$msg);
+                       $msg = strip_tags($msg);
+
+                       // quotes not working - let's try this
+                       $msg = html_entity_decode($msg);
+                       if (( strlen($msg) > $max_char) && $max_char > 0) {
+                               $shortlink = short_link( $b['plink'] );
+                               // the new message will be shortened such that "... $shortlink"
+                               // will fit into the character limit
+                               $msg = nl2br(substr($msg, 0, $max_char-strlen($shortlink)-4));
+                               $msg = str_replace(array('<br>','<br />'),' ',$msg);
+                               $e = explode(' ', $msg);
+                               //  remove the last word from the cut down message to 
+                               //  avoid sending cut words to the MicroBlog
+                               array_pop($e);
+                               $msg = implode(' ', $e);
+                               $msg .= '... ' . $shortlink;
+                       }
 
-               $msg = trim($msg);
+                       $msg = trim($msg);
+               } else
+                       $msg = twitter_shortenmsg($b);
 
                // and now tweet it :-)
                if(strlen($msg)) {
@@ -384,16 +543,122 @@ function twitter_post_hook(&$a,&$b) {
 function twitter_plugin_admin_post(&$a){
        $consumerkey    =       ((x($_POST,'consumerkey'))              ? notags(trim($_POST['consumerkey']))   : '');
        $consumersecret =       ((x($_POST,'consumersecret'))   ? notags(trim($_POST['consumersecret'])): '');
+        $applicationname = ((x($_POST, 'applicationname')) ? notags(trim($_POST['applicationname'])):'');
        set_config('twitter','consumerkey',$consumerkey);
        set_config('twitter','consumersecret',$consumersecret);
+       set_config('twitter','application_name',$applicationname);
        info( t('Settings updated.'). EOL );
 }
 function twitter_plugin_admin(&$a, &$o){
-       $t = file_get_contents( dirname(__file__). "/admin.tpl" );
+       $t = get_markup_template( "admin.tpl", "addon/twitter/" );
+
        $o = replace_macros($t, array(
                '$submit' => t('Submit'),
                                                                // name, label, value, help, [extra values]
                '$consumerkey' => array('consumerkey', t('Consumer key'),  get_config('twitter', 'consumerkey' ), ''),
-               '$consumersecret' => array('consumersecret', t('Consumer secret'),  get_config('twitter', 'consumersecret' ), '')
+                '$consumersecret' => array('consumersecret', t('Consumer secret'),  get_config('twitter', 'consumersecret' ), ''),
+                '$applicationname' => array('applicationname', t('Name of the Twitter Application'), get_config('twitter','application_name'),t('set this to avoid mirroring postings from ~friendica back to ~friendica'))
        ));
 }
+
+function twitter_cron($a,$b) {
+       $last = get_config('twitter','last_poll');
+
+       $poll_interval = intval(get_config('twitter','poll_interval'));
+       if(! $poll_interval)
+               $poll_interval = TWITTER_DEFAULT_POLL_INTERVAL;
+
+       if($last) {
+               $next = $last + ($poll_interval * 60);
+               if($next > time()) {
+                       logger('twitter: poll intervall not reached');
+                       return;
+               }
+       }
+       logger('twitter: cron_start');
+
+       $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'mirror_posts' AND `v` = '1' ORDER BY RAND() ");
+       if(count($r)) {
+               foreach($r as $rr) {
+                       logger('twitter: fetching for user '.$rr['uid']);
+                       twitter_fetchtimeline($a, $rr['uid']);
+               }
+       }
+
+       logger('twitter: cron_end');
+
+       set_config('twitter','last_poll', time());
+}
+
+function twitter_fetchtimeline($a, $uid) {
+       $ckey    = get_config('twitter', 'consumerkey');
+       $csecret = get_config('twitter', 'consumersecret');
+       $otoken  = get_pconfig($uid, 'twitter', 'oauthtoken');
+       $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
+       $lastid  = get_pconfig($uid, 'twitter', 'lastid');
+
+       $application_name  = get_config('twitter', 'application_name');
+
+       if ($application_name == "")
+               $application_name = $a->get_hostname();
+
+       require_once('library/twitteroauth.php');
+       $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
+
+       $parameters = array("exclude_replies" => true, "trim_user" => true, "contributor_details" => false, "include_rts" => false);
+
+       $first_time = ($lastid == "");
+
+       if ($lastid <> "")
+               $parameters["since_id"] = $lastid;
+
+       $items = $connection->get('statuses/user_timeline', $parameters);
+
+       if (!is_array($items))
+               return;
+
+       $posts = array_reverse($items);
+
+        if (count($posts)) {
+           foreach ($posts as $post) {
+               if ($post->id_str > $lastid)
+                       $lastid = $post->id_str;
+
+               if ($first_time)
+                       continue;
+
+               if (!strpos($post->source, $application_name)) {
+                       $_SESSION["authenticated"] = true;
+                       $_SESSION["uid"] = $uid;
+
+                       $_REQUEST["type"] = "wall";
+                       $_REQUEST["api_source"] = true;
+                       $_REQUEST["profile_uid"] = $uid;
+                       $_REQUEST["source"] = "Twitter";
+
+                       //$_REQUEST["date"] = $post->created_at;
+
+                       $_REQUEST["body"] = $post->text;
+                       if (is_string($post->place->name))
+                               $_REQUEST["location"] = $post->place->name;
+
+                       if (is_string($post->place->full_name))
+                               $_REQUEST["location"] = $post->place->full_name;
+
+                       if (is_array($post->geo->coordinates))
+                               $_REQUEST["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
+
+                       if (is_array($post->coordinates->coordinates))
+                               $_REQUEST["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
+
+                       //print_r($_REQUEST);
+                       logger('twitter: posting for user '.$uid);
+
+                       require_once('mod/item.php');
+                       item_post($a);
+
+                }
+            }
+       }
+       set_pconfig($uid, 'twitter', 'lastid', $lastid);
+}
diff --git a/twitter/view/admin.tpl b/twitter/view/admin.tpl
new file mode 100644 (file)
index 0000000..b89f51b
--- /dev/null
@@ -0,0 +1,4 @@
+{{ inc field_input.tpl with $field=$consumerkey }}{{ endinc }}
+{{ inc field_input.tpl with $field=$consumersecret }}{{ endinc }}
+{{ inc field_input.tpl with $field=$applicationname }}{{ endinc }}
+<div class="submit"><input type="submit" name="page_site" value="$submit" /></div>
diff --git a/twitter/view/smarty3/admin.tpl b/twitter/view/smarty3/admin.tpl
new file mode 100644 (file)
index 0000000..554ed5a
--- /dev/null
@@ -0,0 +1,4 @@
+{{include file="field_input.tpl" field=$consumerkey}}
+{{include file="field_input.tpl" field=$consumersecret}}
+{{include file="field_input.tpl" field=$applicationname}}
+<div class="submit"><input type="submit" name="page_site" value="{{$submit}}" /></div>
index 4aa58096d8ce8de26c9e0fa783fb64922bdb1ea2..7a758b00d0714884bd790f37e5123e3b2d74e9b4 100755 (executable)
Binary files a/uhremotestorage.tgz and b/uhremotestorage.tgz differ
diff --git a/uhremotestorage/settings.tpl b/uhremotestorage/settings.tpl
deleted file mode 100755 (executable)
index 22d7d60..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<div class="settings-block">
-       <h3>$title</h3>
-       <p>$desc</p>
-       {{ inc field_input.tpl with $field=$url }}{{ endinc }}
-       {{ inc field_input.tpl with $field=$auth }}{{ endinc }}
-       {{ inc field_select.tpl with $field=$api }}{{ endinc }}
-       <div class="submit"><input type="submit" name="page_site" value="$submit" /></div>      
-
-</div>
index a2a8cc3dd107cf4ccdc0ca2e6c5416b82e14eb0d..85d6b13e8c34186c60a8775686d65eb4a6715af1 100755 (executable)
@@ -78,7 +78,7 @@ function uhremotestorage_settings($a, &$s){
                'Dropbox' => 'Dropbox',
        );
        */
-       $tpl = file_get_contents(dirname(__file__)."/settings.tpl");
+       $tpl = get_markup_template("settings.tpl", "addon/uhremotestorage/");
        $s .= replace_macros($tpl, array(
                '$title' => 'Unhosted remote storage',
                '$desc' => sprintf( t('Allow to use your friendica id (%s) to connecto to external unhosted-enabled storage (like ownCloud). See <a href="http://www.w3.org/community/unhosted/wiki/RemoteStorage#WebFinger">RemoteStorage WebFinger</a>'), $uid ),
diff --git a/uhremotestorage/view/settings.tpl b/uhremotestorage/view/settings.tpl
new file mode 100644 (file)
index 0000000..22d7d60
--- /dev/null
@@ -0,0 +1,9 @@
+<div class="settings-block">
+       <h3>$title</h3>
+       <p>$desc</p>
+       {{ inc field_input.tpl with $field=$url }}{{ endinc }}
+       {{ inc field_input.tpl with $field=$auth }}{{ endinc }}
+       {{ inc field_select.tpl with $field=$api }}{{ endinc }}
+       <div class="submit"><input type="submit" name="page_site" value="$submit" /></div>      
+
+</div>
diff --git a/uhremotestorage/view/smarty3/settings.tpl b/uhremotestorage/view/smarty3/settings.tpl
new file mode 100644 (file)
index 0000000..9a0a55f
--- /dev/null
@@ -0,0 +1,9 @@
+<div class="settings-block">
+       <h3>{{$title}}</h3>
+       <p>{{$desc}}</p>
+       {{include file="field_input.tpl" field=$url}}
+       {{include file="field_input.tpl" field=$auth}}
+       {{include file="field_select.tpl" field=$api}}
+       <div class="submit"><input type="submit" name="page_site" value="{{$submit}}" /></div>  
+
+</div>
index 2ace240a6fef124011513f485166f93df404300f..16d587a7ddbeb485ea6c1080d049ef031ed4495a 100644 (file)
Binary files a/viewsrc.tgz and b/viewsrc.tgz differ
index f165e9c5353ba73dd63bf2537bb691074eccb0d7..9366930f00e133b21c2150d9575a4f06f619e57d 100644 (file)
@@ -25,7 +25,9 @@ function viewsrc_page_end(&$a, &$o){
        $a->page['htmlhead'] .= <<< EOS
        <script>
                $(function(){
-                       $('a[href*="/viewsrc/"]').fancybox();
+                       $('a[href*="/viewsrc/"]').each(function() {
+                               $(this).colorbox($(this).attr('href'));
+                       });
                });
        </script>
 EOS;
index f3b1857838ac7c0594cf2b9c5c6c5a45f5296ec1..d89204f59ae1bec973dba92e42bdac79fa7d9d26 100755 (executable)
Binary files a/widgets.tgz and b/widgets.tgz differ
diff --git a/widgets/settings.tpl b/widgets/settings.tpl
deleted file mode 100755 (executable)
index 9d0f21d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<div class="settings-block">
-       <h3 class="settings-heading">$title</h3>
-       <div class='field noedit'>
-               <label>$label</label>
-               <tt>$key</tt>
-       </div>
-       
-       <div class="settings-submit-wrapper">
-               <input type="submit" value="$submit" class="settings-submit" name="widgets-submit" />
-       </div>
-       
-       <h4>$widgets_h</h4>
-       <ul>
-               {{ for $widgets as $w }}
-                       <li><a href="$baseurl/widgets/$w.0/?k=$key&p=1">$w.1</a></li>
-               {{ endfor }}
-       </ul>
-       
-</div>
diff --git a/widgets/view/settings.tpl b/widgets/view/settings.tpl
new file mode 100755 (executable)
index 0000000..9d0f21d
--- /dev/null
@@ -0,0 +1,19 @@
+<div class="settings-block">
+       <h3 class="settings-heading">$title</h3>
+       <div class='field noedit'>
+               <label>$label</label>
+               <tt>$key</tt>
+       </div>
+       
+       <div class="settings-submit-wrapper">
+               <input type="submit" value="$submit" class="settings-submit" name="widgets-submit" />
+       </div>
+       
+       <h4>$widgets_h</h4>
+       <ul>
+               {{ for $widgets as $w }}
+                       <li><a href="$baseurl/widgets/$w.0/?k=$key&p=1">$w.1</a></li>
+               {{ endfor }}
+       </ul>
+       
+</div>
diff --git a/widgets/view/smarty3/settings.tpl b/widgets/view/smarty3/settings.tpl
new file mode 100644 (file)
index 0000000..017fa12
--- /dev/null
@@ -0,0 +1,19 @@
+<div class="settings-block">
+       <h3 class="settings-heading">{{$title}}</h3>
+       <div class='field noedit'>
+               <label>{{$label}}</label>
+               <tt>{{$key}}</tt>
+       </div>
+       
+       <div class="settings-submit-wrapper">
+               <input type="submit" value="{{$submit}}" class="settings-submit" name="widgets-submit" />
+       </div>
+       
+       <h4>{{$widgets_h}}</h4>
+       <ul>
+               {{foreach $widgets as $w}}
+                       <li><a href="{{$baseurl}}/widgets/{{$w.0}}/?k={{$key}}&p=1">{{$w.1}}</a></li>
+               {{/foreach}}
+       </ul>
+       
+</div>
diff --git a/widgets/view/smarty3/widget_like.tpl b/widgets/view/smarty3/widget_like.tpl
new file mode 100644 (file)
index 0000000..ad52957
--- /dev/null
@@ -0,0 +1,3 @@
+<style>body {font-size: 0.8em; margin: 0px; padding: 0px;}</style>
+<span class='f9k_like' title="{{$strlike}}">{{$like}} <img src="{{$baseurl}}/images/like.gif" alt="like"/></span> 
+<span class='f9k_dislike' title="{{$strdislike}}">{{$dislike}} <img src="{{$baseurl}}/images/dislike.gif" alt="dislike"/></span>
diff --git a/widgets/view/widget_like.tpl b/widgets/view/widget_like.tpl
new file mode 100755 (executable)
index 0000000..3c26d1d
--- /dev/null
@@ -0,0 +1,3 @@
+<style>body {font-size: 0.8em; margin: 0px; padding: 0px;}</style>
+<span class='f9k_like' title="$strlike">$like <img src="$baseurl/images/like.gif" alt="like"/></span> 
+<span class='f9k_dislike' title="$strdislike">$dislike <img src="$baseurl/images/dislike.gif" alt="dislike"/></span>
index 649d4a767ec1b4d65311dc83ae304953c614a731..8f356da976b856b9326a3ceb217be18086314802 100755 (executable)
@@ -52,7 +52,8 @@ function like_widget_content(&$a, $conf){
        
        $o = "";
        
-       $t = file_get_contents( dirname(__file__). "/widget_like.tpl" );
+#      $t = file_get_contents( dirname(__file__). "/widget_like.tpl" );
+       $t = get_markup_template("widget_like.tpl", "addon/widgets/");
        $o .= replace_macros($t, array(
                '$like'         => $likes,
                '$strlike'      => sprintf( tt("%d person likes this", "%d people like this", $likes), $likes),
diff --git a/widgets/widget_like.tpl b/widgets/widget_like.tpl
deleted file mode 100755 (executable)
index 3c26d1d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<style>body {font-size: 0.8em; margin: 0px; padding: 0px;}</style>
-<span class='f9k_like' title="$strlike">$like <img src="$baseurl/images/like.gif" alt="like"/></span> 
-<span class='f9k_dislike' title="$strdislike">$dislike <img src="$baseurl/images/dislike.gif" alt="dislike"/></span>
index 47a6e48a6fe6deea6903fb25b3d8f4244206112a..72534ce3bb75863556051ffbbbe91c13738eacc0 100755 (executable)
@@ -51,7 +51,8 @@ function widgets_settings(&$a,&$o) {
 
        
        
-       $t = file_get_contents( dirname(__file__). "/settings.tpl" );
+#      $t = file_get_contents( dirname(__file__). "/settings.tpl" );
+       $t = get_markup_template("settings.tpl", "addon/widgets/");
        $o .= replace_macros($t, array(
                '$submit' => t('Generate new key'),
                '$baseurl' => $a->get_baseurl(),